Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.content.SharedPreferences; | 8 import android.content.SharedPreferences; |
| 9 import android.content.pm.PackageInfo; | 9 import android.content.pm.PackageInfo; |
| 10 import android.content.pm.PackageManager; | 10 import android.content.pm.PackageManager; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 | 29 |
| 30 /** | 30 /** |
| 31 * Handles extracting the necessary resources bundled in an APK and moving them to a location on | 31 * Handles extracting the necessary resources bundled in an APK and moving them to a location on |
| 32 * the file system accessible from the native code. | 32 * the file system accessible from the native code. |
| 33 */ | 33 */ |
| 34 public class ResourceExtractor { | 34 public class ResourceExtractor { |
| 35 | 35 |
| 36 private static final String LOGTAG = "ResourceExtractor"; | 36 private static final String LOGTAG = "ResourceExtractor"; |
| 37 private static final String LAST_LANGUAGE = "Last language"; | 37 private static final String LAST_LANGUAGE = "Last language"; |
| 38 private static final String PAK_FILENAMES = "Pak filenames"; | 38 private static final String PAK_FILENAMES = "Pak filenames"; |
| 39 private static final String ICU_DATA_FILENAME = "icudtl.dat"; | |
| 39 | 40 |
| 40 private static String[] sMandatoryPaks = null; | 41 private static String[] sMandatoryPaks = null; |
| 41 | 42 |
| 42 // By default, we attempt to extract a pak file for the users | 43 // By default, we attempt to extract a pak file for the users |
| 43 // current device locale. Use setExtractImplicitLocale() to | 44 // current device locale. Use setExtractImplicitLocale() to |
| 44 // change this behavior. | 45 // change this behavior. |
| 45 private static boolean sExtractImplicitLocalePak = true; | 46 private static boolean sExtractImplicitLocalePak = true; |
| 46 | 47 |
| 47 private class ExtractTask extends AsyncTask<Void, Void, Void> { | 48 private class ExtractTask extends AsyncTask<Void, Void, Void> { |
| 48 private static final int BUFFER_SIZE = 16 * 1024; | 49 private static final int BUFFER_SIZE = 16 * 1024; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 } | 90 } |
| 90 | 91 |
| 91 if (sExtractImplicitLocalePak) { | 92 if (sExtractImplicitLocalePak) { |
| 92 if (p.length() > 0) p.append('|'); | 93 if (p.length() > 0) p.append('|'); |
| 93 // As well as the minimum required set of .paks above, we'll als o add all .paks that | 94 // As well as the minimum required set of .paks above, we'll als o add all .paks that |
| 94 // we have for the user's currently selected language. | 95 // we have for the user's currently selected language. |
| 95 | 96 |
| 96 p.append(currentLanguage); | 97 p.append(currentLanguage); |
| 97 p.append("(-\\w+)?\\.pak"); | 98 p.append("(-\\w+)?\\.pak"); |
| 98 } | 99 } |
| 100 | |
| 99 Pattern paksToInstall = Pattern.compile(p.toString()); | 101 Pattern paksToInstall = Pattern.compile(p.toString()); |
| 100 | 102 |
| 101 AssetManager manager = mContext.getResources().getAssets(); | 103 AssetManager manager = mContext.getResources().getAssets(); |
| 102 try { | 104 try { |
| 103 // Loop through every asset file that we have in the APK, and lo ok for the | 105 // Loop through every asset file that we have in the APK, and lo ok for the |
| 104 // ones that we need to extract by trying to match the Patterns that we | 106 // ones that we need to extract by trying to match the Patterns that we |
| 105 // created above. | 107 // created above. |
| 106 byte[] buffer = null; | 108 byte[] buffer = null; |
| 107 String[] files = manager.list(""); | 109 String[] files = manager.list(""); |
| 108 for (String file : files) { | 110 for (String file : files) { |
| 109 if (!paksToInstall.matcher(file).matches()) { | 111 if (!paksToInstall.matcher(file).matches()) { |
| 110 continue; | 112 continue; |
| 111 } | 113 } |
| 112 File output = new File(mOutputDir, file); | 114 boolean isICUData = file.equals(ICU_DATA_FILENAME); |
| 115 File output = new File(isICUData ? mAppDataDir : mOutputDir, file); | |
| 113 if (output.exists()) { | 116 if (output.exists()) { |
| 114 continue; | 117 continue; |
| 115 } | 118 } |
| 116 | 119 |
| 117 InputStream is = null; | 120 InputStream is = null; |
| 118 OutputStream os = null; | 121 OutputStream os = null; |
| 119 try { | 122 try { |
| 120 is = manager.open(file); | 123 is = manager.open(file); |
| 121 os = new FileOutputStream(output); | 124 os = new FileOutputStream(output); |
| 122 Log.i(LOGTAG, "Extracting resource " + file); | 125 Log.i(LOGTAG, "Extracting resource " + file); |
| 123 if (buffer == null) { | 126 if (buffer == null) { |
| 124 buffer = new byte[BUFFER_SIZE]; | 127 buffer = new byte[BUFFER_SIZE]; |
| 125 } | 128 } |
| 126 | 129 |
| 127 int count = 0; | 130 int count = 0; |
| 128 while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { | 131 while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { |
| 129 os.write(buffer, 0, count); | 132 os.write(buffer, 0, count); |
| 130 } | 133 } |
| 131 os.flush(); | 134 os.flush(); |
| 132 | 135 |
| 133 // Ensure something reasonable was written. | 136 // Ensure something reasonable was written. |
| 134 if (output.length() == 0) { | 137 if (output.length() == 0) { |
| 135 throw new IOException(file + " extracted with 0 leng th!"); | 138 throw new IOException(file + " extracted with 0 leng th!"); |
| 136 } | 139 } |
| 137 | 140 |
| 138 filenames.add(file); | 141 if (!isICUData) { |
| 142 filenames.add(file); | |
| 143 } else { | |
| 144 // icudata needs to be accessed by a renderer proces s. | |
| 145 output.setReadable(true, false); | |
| 146 } | |
| 139 } finally { | 147 } finally { |
| 140 try { | 148 try { |
| 141 if (is != null) { | 149 if (is != null) { |
| 142 is.close(); | 150 is.close(); |
| 143 } | 151 } |
| 144 } finally { | 152 } finally { |
| 145 if (os != null) { | 153 if (os != null) { |
| 146 os.close(); | 154 os.close(); |
| 147 } | 155 } |
| 148 } | 156 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 return expectedTimestamp; | 224 return expectedTimestamp; |
| 217 } | 225 } |
| 218 | 226 |
| 219 // timestamp file is already up-to date. | 227 // timestamp file is already up-to date. |
| 220 return null; | 228 return null; |
| 221 } | 229 } |
| 222 } | 230 } |
| 223 | 231 |
| 224 private final Context mContext; | 232 private final Context mContext; |
| 225 private ExtractTask mExtractTask; | 233 private ExtractTask mExtractTask; |
| 234 private final File mAppDataDir; | |
| 226 private final File mOutputDir; | 235 private final File mOutputDir; |
| 227 | 236 |
| 228 private static ResourceExtractor sInstance; | 237 private static ResourceExtractor sInstance; |
| 229 | 238 |
| 230 public static ResourceExtractor get(Context context) { | 239 public static ResourceExtractor get(Context context) { |
| 231 if (sInstance == null) { | 240 if (sInstance == null) { |
| 232 sInstance = new ResourceExtractor(context); | 241 sInstance = new ResourceExtractor(context); |
| 233 } | 242 } |
| 234 return sInstance; | 243 return sInstance; |
| 235 } | 244 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 256 * pak files specified in sMandatoryPaks. | 265 * pak files specified in sMandatoryPaks. |
| 257 */ | 266 */ |
| 258 public static void setExtractImplicitLocaleForTesting(boolean extract) { | 267 public static void setExtractImplicitLocaleForTesting(boolean extract) { |
| 259 assert (sInstance == null || sInstance.mExtractTask == null) | 268 assert (sInstance == null || sInstance.mExtractTask == null) |
| 260 : "Must be called before startExtractingResources is called"; | 269 : "Must be called before startExtractingResources is called"; |
| 261 sExtractImplicitLocalePak = extract; | 270 sExtractImplicitLocalePak = extract; |
| 262 } | 271 } |
| 263 | 272 |
| 264 private ResourceExtractor(Context context) { | 273 private ResourceExtractor(Context context) { |
| 265 mContext = context; | 274 mContext = context; |
| 275 mAppDataDir = getAppDataDirFromContext(mContext); | |
| 266 mOutputDir = getOutputDirFromContext(mContext); | 276 mOutputDir = getOutputDirFromContext(mContext); |
| 267 } | 277 } |
| 268 | 278 |
| 269 public void waitForCompletion() { | 279 public void waitForCompletion() { |
| 270 if (shouldSkipPakExtraction()) { | 280 if (shouldSkipPakExtraction()) { |
| 271 return; | 281 return; |
| 272 } | 282 } |
| 273 | 283 |
| 274 assert mExtractTask != null; | 284 assert mExtractTask != null; |
| 275 | 285 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 296 } | 306 } |
| 297 | 307 |
| 298 if (shouldSkipPakExtraction()) { | 308 if (shouldSkipPakExtraction()) { |
| 299 return; | 309 return; |
| 300 } | 310 } |
| 301 | 311 |
| 302 mExtractTask = new ExtractTask(); | 312 mExtractTask = new ExtractTask(); |
| 303 mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | 313 mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
| 304 } | 314 } |
| 305 | 315 |
| 316 public static File getAppDataDirFromContext(Context context) { | |
| 317 return new File(PathUtils.getDataDirectory(context.getApplicationContext ())); | |
| 318 } | |
|
Yaron
2014/02/20 18:15:01
nit: add ws line after
| |
| 306 public static File getOutputDirFromContext(Context context) { | 319 public static File getOutputDirFromContext(Context context) { |
| 307 return new File(PathUtils.getDataDirectory(context.getApplicationContext ()), "paks"); | 320 return new File(getAppDataDirFromContext(context), "paks"); |
| 308 } | 321 } |
| 309 | 322 |
| 310 public static void deleteFiles(Context context) { | 323 public static void deleteFiles(Context context) { |
| 324 File icudata = new File(getAppDataDirFromContext(context), ICU_DATA_FILE NAME); | |
| 325 if (icudata.exists() && !icudata.delete()) { | |
| 326 Log.w(LOGTAG, "Unable to remove the icudata " + icudata.getName()); | |
| 327 } | |
| 311 File dir = getOutputDirFromContext(context); | 328 File dir = getOutputDirFromContext(context); |
| 312 if (dir.exists()) { | 329 if (dir.exists()) { |
| 313 File[] files = dir.listFiles(); | 330 File[] files = dir.listFiles(); |
| 314 for (File file : files) { | 331 for (File file : files) { |
| 315 if (!file.delete()) { | 332 if (!file.delete()) { |
| 316 Log.w(LOGTAG, "Unable to remove existing resource " + file.g etName()); | 333 Log.w(LOGTAG, "Unable to remove existing resource " + file.g etName()); |
| 317 } | 334 } |
| 318 } | 335 } |
| 319 } | 336 } |
| 320 } | 337 } |
| 321 | 338 |
| 322 /** | 339 /** |
| 323 * Pak extraction not necessarily required by the embedder; we allow them to skip | 340 * Pak extraction not necessarily required by the embedder; we allow them to skip |
| 324 * this process if they call setMandatoryPaksToExtract with a single empty S tring. | 341 * this process if they call setMandatoryPaksToExtract with a single empty S tring */ |
|
benm (inactive)
2014/02/20 14:13:07
nit: add back the period, and */ onto the next lin
| |
| 325 */ | |
| 326 private static boolean shouldSkipPakExtraction() { | 342 private static boolean shouldSkipPakExtraction() { |
| 327 // Must call setMandatoryPaksToExtract before beginning resource extract ion. | 343 // Must call setMandatoryPaksToExtract before beginning resource extract ion. |
| 328 assert sMandatoryPaks != null; | 344 assert sMandatoryPaks != null; |
| 329 return sMandatoryPaks.length == 1 && "".equals(sMandatoryPaks[0]); | 345 return sMandatoryPaks.length == 1 && "".equals(sMandatoryPaks[0]); |
| 330 } | 346 } |
| 331 } | 347 } |
| OLD | NEW |