Index: sky/shell/android/org/domokit/sky/shell/ResourceExtractor.java |
diff --git a/sky/shell/android/org/domokit/sky/shell/ResourceExtractor.java b/sky/shell/android/org/domokit/sky/shell/ResourceExtractor.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3976bb9dd2124a87dd48ca0daea638107b405f22 |
--- /dev/null |
+++ b/sky/shell/android/org/domokit/sky/shell/ResourceExtractor.java |
@@ -0,0 +1,186 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.domokit.sky.shell; |
+ |
+import android.content.Context; |
+import android.content.pm.PackageInfo; |
+import android.content.pm.PackageManager; |
+import android.content.res.AssetManager; |
+import android.os.AsyncTask; |
+import android.util.Log; |
+ |
+import org.chromium.base.PathUtils; |
+ |
+import java.io.File; |
+import java.io.FileOutputStream; |
+import java.io.FilenameFilter; |
+import java.io.IOException; |
+import java.io.InputStream; |
+import java.io.OutputStream; |
+import java.util.HashSet; |
+import java.util.concurrent.CancellationException; |
+import java.util.concurrent.ExecutionException; |
+ |
+/** |
+ * A class to intialize the native code. |
+ **/ |
+public class ResourceExtractor { |
+ private static final String TAG = "ResourceExtractor"; |
+ private static final String TIMESTAMP_PREFIX = "res_timestamp-"; |
+ |
+ private class ExtractTask extends AsyncTask<Void, Void, Void> { |
+ private static final int BUFFER_SIZE = 16 * 1024; |
+ |
+ public ExtractTask() { } |
+ |
+ private void extractResources() { |
+ final File dataDir = new File(PathUtils.getDataDirectory(mContext)); |
+ |
+ final String timestamp = checkTimestamp(dataDir); |
+ if (timestamp != null) { |
+ deleteFiles(); |
+ } |
+ |
+ final AssetManager manager = mContext.getResources().getAssets(); |
+ try { |
+ byte[] buffer = null; |
+ final String[] assets = manager.list(""); |
+ for (String asset : assets) { |
+ if (!mResources.contains(asset)) |
+ continue; |
+ final File output = new File(dataDir, asset); |
+ if (output.exists()) |
+ continue; |
+ InputStream is = null; |
+ OutputStream os = null; |
+ try { |
+ is = manager.open(asset); |
+ os = new FileOutputStream(output); |
+ if (buffer == null) { |
+ buffer = new byte[BUFFER_SIZE]; |
+ } |
+ |
+ int count = 0; |
+ while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { |
+ os.write(buffer, 0, count); |
+ } |
+ os.flush(); |
+ } finally { |
+ try { |
+ if (is != null) { |
+ is.close(); |
+ } |
+ } finally { |
+ if (os != null) { |
+ os.close(); |
+ } |
+ } |
+ } |
+ } |
+ } catch (IOException e) { |
+ Log.w(TAG, "Exception unpacking resources: " + e.getMessage()); |
+ deleteFiles(); |
+ return; |
+ } |
+ |
+ if (timestamp != null) { |
+ try { |
+ new File(dataDir, timestamp).createNewFile(); |
+ } catch (IOException e) { |
+ Log.w(TAG, "Failed to write resource timestamp"); |
+ } |
+ } |
+ } |
+ |
+ private String checkTimestamp(File dataDir) { |
+ PackageManager packageManager = mContext.getPackageManager(); |
+ PackageInfo packageInfo = null; |
+ |
+ try { |
+ packageInfo = packageManager.getPackageInfo(mContext.getPackageName(), 0); |
+ } catch (PackageManager.NameNotFoundException e) { |
+ return TIMESTAMP_PREFIX; |
+ } |
+ |
+ if (packageInfo == null) { |
+ return TIMESTAMP_PREFIX; |
+ } |
+ |
+ String expectedTimestamp = |
+ TIMESTAMP_PREFIX + packageInfo.versionCode + "-" + packageInfo.lastUpdateTime; |
+ |
+ final String[] existingTimestamps = getExistingTimestamps(dataDir); |
+ if (existingTimestamps.length != 1 |
+ || !expectedTimestamp.equals(existingTimestamps[0])) { |
+ return expectedTimestamp; |
+ } |
+ |
+ return null; |
+ } |
+ |
+ @Override |
+ protected Void doInBackground(Void... unused) { |
+ extractResources(); |
+ return null; |
+ } |
+ } |
+ |
+ private final Context mContext; |
+ private final HashSet<String> mResources; |
+ private ExtractTask mExtractTask; |
+ |
+ public ResourceExtractor(Context context) { |
+ mContext = context; |
+ mResources = new HashSet<String>(); |
+ } |
+ |
+ public void addResources(String[] resources) { |
+ for (String resource : resources) { |
+ mResources.add(resource); |
+ } |
+ } |
+ |
+ public void start() { |
+ assert mExtractTask == null; |
+ mExtractTask = new ExtractTask(); |
+ mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
+ } |
+ |
+ public void waitForCompletion() { |
+ assert mExtractTask != null; |
+ |
+ try { |
+ mExtractTask.get(); |
+ } catch (CancellationException e) { |
+ deleteFiles(); |
+ } catch (ExecutionException e2) { |
+ deleteFiles(); |
+ } catch (InterruptedException e3) { |
+ deleteFiles(); |
+ } |
+ } |
+ |
+ private String[] getExistingTimestamps(File dataDir) { |
+ return dataDir.list(new FilenameFilter() { |
+ @Override |
+ public boolean accept(File dir, String name) { |
+ return name.startsWith(TIMESTAMP_PREFIX); |
+ } |
+ }); |
+ } |
+ |
+ private void deleteFiles() { |
+ final File dataDir = new File(PathUtils.getDataDirectory(mContext)); |
+ for (String resource : mResources) { |
+ final File file = new File(dataDir, resource); |
+ if (file.exists()) { |
+ file.delete(); |
+ } |
+ } |
+ for (String timestamp : getExistingTimestamps(dataDir)) { |
+ new File(dataDir, timestamp).delete(); |
+ } |
+ } |
+} |