Auto merge of #15396 - zhuowei:android-extract-resources, r=larsbergstrom

android: extract resources to external storage on first launch

<!-- Please describe your changes on the following line: -->

If /sdcard/servo doesn't exist, extract it from the assets/ folder of the APK. This fixes issue #12129.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #12129 (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

I tested this on a Nexus 6P running Android 7.1: on launch, the app correctly detects that /sdcard/servo is missing, extracts the contents from assets/, and launches without force closing.

This is my first Servo pull request, so apologies in advance if I'm doing something wrong. Also, I was unable to build the entirety of Servo from source (complains about missing freetype), so I just built the Java portion separately; would that impact anything?

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15396)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-02-09 12:27:12 -08:00 committed by GitHub
commit 349971b380

View file

@ -3,10 +3,16 @@ import android.app.NativeActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.System;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class MainActivity extends android.app.NativeActivity {
@ -37,6 +43,13 @@ public class MainActivity extends android.app.NativeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
if (needsToExtractAssets()) {
try {
extractAssets();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
if (intent.getAction().equals(Intent.ACTION_VIEW)) {
@ -62,4 +75,42 @@ public class MainActivity extends android.app.NativeActivity {
android.os.Process.killProcess(pid);
System.exit(0);
}
private boolean needsToExtractAssets() {
// todo: also force a reextract when the resources are updated.
return !(new File("/sdcard/servo").exists());
}
/**
* extracts assets/ in the APK to /sdcard/servo.
*/
private void extractAssets() throws IOException {
ZipFile zipFile = null;
File targetDir = new File("/sdcard/servo");
try {
zipFile = new ZipFile(this.getApplicationInfo().sourceDir);
for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
ZipEntry entry = e.nextElement();
if (entry.isDirectory() || !entry.getName().startsWith("assets/")) {
continue;
}
File targetFile = new File(targetDir, entry.getName().substring("assets/".length()));
targetFile.getParentFile().mkdirs();
byte[] tempBuffer = new byte[(int)entry.getSize()];
BufferedInputStream is = null;
FileOutputStream os = null;
try {
is = new BufferedInputStream(zipFile.getInputStream(entry));
os = new FileOutputStream(targetFile);
is.read(tempBuffer);
os.write(tempBuffer);
} finally {
if (is != null) is.close();
if (os != null) os.close();
}
}
} finally {
if (zipFile != null) zipFile.close();
}
}
}