mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1234629 - Part 1: Create bouncer APK for OTA distribution installs. r=margaret,gps
This commit produces an "install bouncer" APK which is a "hollow shell" that looks like the main Fennec APK. In particular, both APKs have: * the same Android package name (application id); and * the same set of <permission>, <uses-permission>, and <uses-feature> blocks in their manifests. The bouncer APK must always have an android:versionCode smaller than the main Fennec APK; for now, we will just bump that manually mobile/android/bouncer/moz.build. --HG-- rename : mobile/android/javaaddons/Makefile.in => mobile/android/bouncer/Makefile.in rename : mobile/android/app/assets/example_asset.txt => mobile/android/bouncer/assets/example_asset.txt rename : mobile/android/javaaddons/moz.build => mobile/android/bouncer/moz.build rename : mobile/android/base/resources/drawable-v21/logo.xml => mobile/android/bouncer/res/drawable-v21/logo.xml rename : mobile/android/base/resources/drawable/logo.xml => mobile/android/bouncer/res/drawable/logo.xml extra : commitid : 1XkuX1F0pMb extra : rebase_source : c49ac53697927b0f3d1ee47bc1e7035c1b465e99 extra : source : aaa420ed66d754ecc17b19f5a12297d24371f1ca extra : histedit_source : 0e3e2fa225c48ba48df72ff116fd62a7b1ef5ed2
This commit is contained in:
parent
9069995ab8
commit
d466d2939f
@ -8540,6 +8540,7 @@ AC_SUBST(MOZ_DISABLE_GECKOVIEW)
|
||||
AC_SUBST(MOZ_ANDROID_GCM)
|
||||
AC_SUBST(MOZ_ANDROID_GECKOLIBS_AAR)
|
||||
AC_SUBST(MOZ_ANDROID_SEARCH_ACTIVITY)
|
||||
AC_SUBST(MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER)
|
||||
AC_SUBST(MOZ_ANDROID_MLS_STUMBLER)
|
||||
AC_SUBST(MOZ_ANDROID_DOWNLOADS_INTEGRATION)
|
||||
AC_SUBST(MOZ_ANDROID_APPLICATION_CLASS)
|
||||
|
@ -886,9 +886,13 @@ ANDROID_ASSETS_DIRS += [
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ANDROID_DISTRIBUTION_DIRECTORY']:
|
||||
ANDROID_ASSETS_DIRS += [
|
||||
'%' + CONFIG['MOZ_ANDROID_DISTRIBUTION_DIRECTORY'] + '/assets',
|
||||
]
|
||||
# If you change this, also change its equivalent in mobile/android/bouncer.
|
||||
if not CONFIG['MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER']:
|
||||
# If we are packaging the bouncer, it will have the distribution, so don't put
|
||||
# it in the main APK as well.
|
||||
ANDROID_ASSETS_DIRS += [
|
||||
'%' + CONFIG['MOZ_ANDROID_DISTRIBUTION_DIRECTORY'] + '/assets',
|
||||
]
|
||||
|
||||
# We do not expose MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN here because that
|
||||
# would leak the value to build logs. Instead we expose the token quietly where
|
||||
|
54
mobile/android/bouncer/AndroidManifest.xml.in
Normal file
54
mobile/android/bouncer/AndroidManifest.xml.in
Normal file
@ -0,0 +1,54 @@
|
||||
#filter substitution
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="@ANDROID_PACKAGE_NAME@"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="@ANDROID_VERSION_CODE@"
|
||||
android:versionName="@MOZ_APP_VERSION@"
|
||||
#ifdef MOZ_ANDROID_SHARED_ID
|
||||
android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
|
||||
#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="23"/>
|
||||
|
||||
<!-- The bouncer APK and the main APK should define the same set of
|
||||
<permission>, <uses-permission>, and <uses-feature> elements. This reduces
|
||||
the likelihood of permission-related surprises when installing the main APK
|
||||
on top of a pre-installed bouncer APK. Add such shared elements in the
|
||||
fileincluded here, so that they can be referenced by both APKs. -->
|
||||
#include ../base/FennecManifest_permissions.xml.in
|
||||
|
||||
<application android:label="@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="@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"
|
||||
android:exported="false" />
|
||||
|
||||
</application>
|
||||
</manifest>
|
25
mobile/android/bouncer/Makefile.in
Normal file
25
mobile/android/bouncer/Makefile.in
Normal file
@ -0,0 +1,25 @@
|
||||
# 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/BouncerService.java \
|
||||
java/org/mozilla/gecko/BrowserApp.java \
|
||||
$(NULL)
|
||||
|
||||
ANDROID_EXTRA_JARS := \
|
||||
$(NULL)
|
||||
|
||||
PP_TARGETS += manifest
|
||||
manifest := $(srcdir)/AndroidManifest.xml.in
|
||||
manifest_TARGET := export
|
||||
# Special 'cuz they are set in mobile/android/defs.mk.
|
||||
manifest_FLAGS += \
|
||||
-DMOZ_ANDROID_SHARED_ID="$(MOZ_ANDROID_SHARED_ID)" \
|
||||
-DMOZ_ANDROID_SHARED_ACCOUNT_TYPE="$(MOZ_ANDROID_SHARED_ACCOUNT_TYPE)" \
|
||||
-DMOZ_ANDROID_SHARED_FXACCOUNT_TYPE="$(MOZ_ANDROID_SHARED_FXACCOUNT_TYPE)" \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(ANDROID_APK_NAME).apk
|
1
mobile/android/bouncer/assets/example_asset.txt
Normal file
1
mobile/android/bouncer/assets/example_asset.txt
Normal file
@ -0,0 +1 @@
|
||||
This is an example asset.
|
@ -0,0 +1,129 @@
|
||||
/* -*- 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[8192];
|
||||
|
||||
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 from assets/distribution/**", e);
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream in = null;
|
||||
for (String path : files) {
|
||||
try {
|
||||
Log.d(LOGTAG, "Copying distribution file: " + path);
|
||||
|
||||
in = getAssets().open(path);
|
||||
|
||||
final File outFile = getDataFile(path);
|
||||
writeStream(in, outFile, 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<>();
|
||||
getFiles(path, paths);
|
||||
return paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively traverse a directory to list paths to all files.
|
||||
*
|
||||
* @param path Directory to traverse.
|
||||
* @param acc Accumulator of paths seen.
|
||||
* @throws IOException
|
||||
*/
|
||||
private void getFiles(String path, List<String> acc) throws IOException {
|
||||
final String[] list = getAssets().list(path);
|
||||
if (list.length > 0) {
|
||||
// We're a directory -- recurse.
|
||||
for (final String file : list) {
|
||||
getFiles(path + "/" + file, acc);
|
||||
}
|
||||
} else {
|
||||
// We're a file -- accumulate.
|
||||
acc.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
private String getDataDir() {
|
||||
return getApplicationInfo().dataDir;
|
||||
}
|
||||
|
||||
private File getDataFile(final String path) {
|
||||
File outFile = new File(getDataDir(), path);
|
||||
File dir = outFile.getParentFile();
|
||||
|
||||
if (dir != null && !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();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/* -*- 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 android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mozilla.bouncer.BouncerService;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// This races distribution installation against the Play Store killing our process to
|
||||
// install the update. We'll live with it. To do better, consider using an Intent to
|
||||
// notify when the service has completed.
|
||||
startService(new Intent(this, BouncerService.class));
|
||||
|
||||
final String appPackageName = Uri.encode(getPackageName());
|
||||
final Uri uri = Uri.parse("market://details?id=" + appPackageName);
|
||||
Log.i(LOGTAG, "Lanching activity with URL: " + uri.toString());
|
||||
|
||||
// It might be more correct to catch failure in case the Play Store isn't installed. The
|
||||
// fallback action is to open the Play Store website... but doing so may offer Firefox as
|
||||
// browser (since even the bouncer offers to view URLs), which will be very confusing.
|
||||
// Therefore, we don't try to be fancy here, and we just fail (silently).
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
|
||||
finish();
|
||||
}
|
||||
}
|
32
mobile/android/bouncer/moz.build
Normal file
32
mobile/android/bouncer/moz.build
Normal file
@ -0,0 +1,32 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# 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 += [
|
||||
'/' + CONFIG['MOZ_BRANDING_DIRECTORY'] + '/res', # For the icon.
|
||||
'res',
|
||||
]
|
||||
|
||||
ANDROID_ASSETS_DIRS += [
|
||||
'assets',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ANDROID_DISTRIBUTION_DIRECTORY']:
|
||||
# If you change this, also change its equivalent in mobile/android/base.
|
||||
ANDROID_ASSETS_DIRS += [
|
||||
'%' + CONFIG['MOZ_ANDROID_DISTRIBUTION_DIRECTORY'] + '/assets',
|
||||
]
|
15
mobile/android/bouncer/res/drawable-v21/logo.xml
Normal file
15
mobile/android/bouncer/res/drawable-v21/logo.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- The action bar scales the application icon to be too large (bug 1132751)
|
||||
so add some padding to prevent it from scaling so much. -->
|
||||
<inset
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/icon"
|
||||
android:insetTop="6dp"
|
||||
android:insetBottom="6dp"
|
||||
android:insetLeft="6dp"
|
||||
android:insetRight="6dp"
|
||||
/>
|
9
mobile/android/bouncer/res/drawable/logo.xml
Normal file
9
mobile/android/bouncer/res/drawable/logo.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- Overidden. -->
|
||||
<bitmap
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/icon"/>
|
@ -93,6 +93,9 @@ MOZ_ANDROID_MLS_STUMBLER=1
|
||||
# Enable adding to the system downloads list.
|
||||
MOZ_ANDROID_DOWNLOADS_INTEGRATION=1
|
||||
|
||||
# Build and package the install bouncer APK by default.
|
||||
MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER=1
|
||||
|
||||
# Use the low-memory GC tuning.
|
||||
export JS_GC_SMALL_CHUNK_SIZE=1
|
||||
|
||||
|
@ -26,6 +26,9 @@ DIRS += [
|
||||
'geckoview_library',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER']:
|
||||
DIRS += ['bouncer'] # No ordering implied with respect to base.
|
||||
|
||||
DIRS += ['../../xulrunner/tools/redit']
|
||||
|
||||
TEST_DIRS += [
|
||||
|
@ -337,6 +337,16 @@ else
|
||||
INNER_ROBOCOP_PACKAGE=echo 'Testing is disabled - No Android Robocop for you'
|
||||
endif
|
||||
|
||||
ifdef MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER
|
||||
UPLOAD_EXTRA_FILES += bouncer.apk
|
||||
|
||||
# Package and release sign the install bouncer APK.
|
||||
INNER_INSTALL_BOUNCER_PACKAGE=\
|
||||
$(call RELEASE_SIGN_ANDROID_APK,$(topobjdir)/mobile/android/bouncer/bouncer-unsigned-unaligned.apk,$(ABS_DIST)/bouncer.apk)
|
||||
else
|
||||
INNER_INSTALL_BOUNCER_PACKAGE=echo 'Install bouncer is disabled - No trampolines for you'
|
||||
endif # MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER
|
||||
|
||||
# Create geckoview_library/geckoview_{assets,library}.zip for third-party GeckoView consumers.
|
||||
ifdef NIGHTLY_BUILD
|
||||
ifndef MOZ_DISABLE_GECKOVIEW
|
||||
@ -478,6 +488,7 @@ INNER_MAKE_PACKAGE = \
|
||||
(echo "*** Error: The R.txt that was built and the R.txt that is being packaged are not the same. Rebuild mobile/android/base and re-package." && exit 1)) && \
|
||||
$(INNER_MAKE_APK) && \
|
||||
$(INNER_ROBOCOP_PACKAGE) && \
|
||||
$(INNER_INSTALL_BOUNCER_PACKAGE) && \
|
||||
$(INNER_MAKE_GECKOLIBS_AAR) && \
|
||||
$(INNER_MAKE_GECKOVIEW_LIBRARY)
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user