Bug 1234629 - Copy distribution files in bouncer APK. f?rnewman draft
authorMargaret Leibovic <margaret.leibovic@gmail.com>
Wed, 23 Dec 2015 13:00:48 -0500
changeset 319111 0686eda5ed80c1773b261f2d29efac9fe172243e
parent 319110 397b8b80870e104372ef2f7da529a7d4d216484f
child 512542 6df36afa3d882afd6281f7f7905cda4d7e5c3a8b
push id8973
push usermleibovic@mozilla.com
push dateTue, 05 Jan 2016 20:54:12 +0000
bugs1234629
milestone46.0a1
Bug 1234629 - Copy distribution files in bouncer APK. f?rnewman
mobile/android/bouncer/AndroidManifest.xml.in
mobile/android/bouncer/Makefile.in
mobile/android/bouncer/java/org/mozilla/bouncer/BouncerActivity.java
mobile/android/bouncer/java/org/mozilla/bouncer/BouncerService.java
mobile/android/bouncer/java/org/mozilla/gecko/BrowserApp.java
mobile/android/bouncer/moz.build
--- a/mobile/android/bouncer/AndroidManifest.xml.in
+++ b/mobile/android/bouncer/AndroidManifest.xml.in
@@ -10,25 +10,36 @@
 #endif
       >
     <uses-sdk android:minSdkVersion="@MOZ_ANDROID_MIN_SDK_VERSION@"
 #ifdef MOZ_ANDROID_MAX_SDK_VERSION
               android:maxSdkVersion="@MOZ_ANDROID_MAX_SDK_VERSION@"
 #endif
               android:targetSdkVersion="22"/>
 
-
     <application android:label="@string/moz_app_displayname"
                  android:icon="@drawable/icon"
                  android:logo="@drawable/logo"
                  android:hardwareAccelerated="true"
                  android:allowBackup="false"
 # The preprocessor does not yet support arbitrary parentheses, so this cannot
 # be parenthesized thus to clarify that the logical AND operator has precedence:
 #   !defined(MOZILLA_OFFICIAL) || (defined(NIGHTLY_BUILD) && defined(MOZ_DEBUG))
 #if !defined(MOZILLA_OFFICIAL) || defined(NIGHTLY_BUILD) && defined(MOZ_DEBUG)
                  android:debuggable="true">
 #else
                  android:debuggable="false">
 #endif
 
+        <activity
+            android:name="@MOZ_ANDROID_BROWSER_INTENT_CLASS@"
+            android:label="@string/moz_app_displayname"
+            android:theme="@android:style/Theme.Translucent">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <service android:name="org.mozilla.bouncer.BouncerService"/>
+
     </application>
 </manifest>
--- a/mobile/android/bouncer/Makefile.in
+++ b/mobile/android/bouncer/Makefile.in
@@ -1,16 +1,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include $(topsrcdir)/config/config.mk
 
 JAVAFILES := \
-	java/org/mozilla/bouncer/BouncerActivity.java \
+	java/org/mozilla/bouncer/BouncerService.java \
+	java/org/mozilla/gecko/BrowserApp.java \
   $(NULL)
 
 ANDROID_EXTRA_JARS := \
   $(NULL)
 
 PP_TARGETS += manifest
 manifest := $(srcdir)/AndroidManifest.xml.in
 manifest_TARGET := export
deleted file mode 100644
--- a/mobile/android/bouncer/java/org/mozilla/bouncer/BouncerActivity.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.bouncer;
-
-import android.app.Activity;
-
-public class BouncerActivity extends Activity {
-}
new file mode 100644
--- /dev/null
+++ b/mobile/android/bouncer/java/org/mozilla/bouncer/BouncerService.java
@@ -0,0 +1,119 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.bouncer;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BouncerService extends IntentService {
+
+    private static final String LOGTAG = "GeckoBouncerService";
+
+    public BouncerService() {
+        super("BouncerService");
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        final byte[] buffer = new byte[1024];
+
+        Log.d(LOGTAG, "Preparing to copy distribution files");
+
+        final List<String> files;
+        try {
+            files = getFiles("distribution");
+        } catch (IOException e) {
+            Log.e(LOGTAG, "Error getting distribution files", e);
+            return;
+        }
+
+        InputStream in = null;
+        for (String path : files) {
+            try {
+                Log.d(LOGTAG, "Copying distribution file: " + path);
+
+                in = getAssets().open(path);
+
+                final File out = getDataFile(path);
+                writeStream(in, out, buffer);
+            } catch (IOException e) {
+                Log.e(LOGTAG, "Error opening distribution input stream from assets", e);
+            } finally {
+                if (in != null) {
+                    try {
+                        in.close();
+                    } catch (IOException e) {
+                        Log.e(LOGTAG, "Error closing distribution input stream", e);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Recursively traverse a directory to list paths to all files.
+     *
+     * @param path Directory to traverse.
+     * @return List of all files in given directory.
+     * @throws IOException
+     */
+    private List<String> getFiles(String path) throws IOException {
+        List<String> paths = new ArrayList<>();
+
+        String[] list = getAssets().list(path);
+        for (String file : list) {
+            String newPath = path + "/" + file;
+            if (getAssets().list(newPath).length > 0) {
+                paths.addAll(getFiles(newPath));
+            } else {
+                paths.add(newPath);
+            }
+        }
+
+        return paths;
+    }
+
+    private String getDataDir() {
+        return getApplicationInfo().dataDir;
+    }
+
+    private File getDataFile(final String path) {
+        File outFile = new File(getDataDir(), path);
+        File dir = outFile.getParentFile();
+
+        if (!dir.exists()) {
+            Log.d(LOGTAG, "Creating " + dir.getAbsolutePath());
+            if (!dir.mkdirs()) {
+                Log.e(LOGTAG, "Unable to create directories: " + dir.getAbsolutePath());
+                return null;
+            }
+        }
+
+        return outFile;
+    }
+
+    private void writeStream(InputStream fileStream, File outFile, byte[] buffer)
+            throws IOException {
+        final OutputStream outStream = new FileOutputStream(outFile);
+        try {
+            int count;
+            while ((count = fileStream.read(buffer)) > 0) {
+                outStream.write(buffer, 0, count);
+            }
+        } finally {
+            outStream.close();
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/bouncer/java/org/mozilla/gecko/BrowserApp.java
@@ -0,0 +1,35 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+import org.mozilla.bouncer.BouncerService;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Bouncer activity version of BrowserApp.
+ *
+ * This class has the same name as org.mozilla.gecko.BrowserApp to preserve
+ * shortcuts created by the bouncer app.
+ */
+public class BrowserApp extends Activity {
+
+    private static final String LOGTAG = "GeckoBouncerActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        startService(new Intent(this, BouncerService.class));
+        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getPackageName())));
+        finish();
+    }
+}
--- a/mobile/android/bouncer/moz.build
+++ b/mobile/android/bouncer/moz.build
@@ -2,16 +2,18 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DEFINES['ANDROID_VERSION_CODE'] = '1'
 
 for var in ('ANDROID_PACKAGE_NAME',
+            'MOZ_ANDROID_BROWSER_INTENT_CLASS',
+            'MOZ_APP_DISPLAYNAME',
             'MOZ_APP_VERSION'):
     DEFINES[var] = CONFIG[var]
 
 ANDROID_APK_NAME = 'bouncer'
 ANDROID_APK_PACKAGE = CONFIG['ANDROID_PACKAGE_NAME']
 
 # Putting branding earlier allows branders to override default resources.
 ANDROID_RES_DIRS += [