Skip to content
Snippets Groups Projects
Commit a2f6cf43 authored by maliu's avatar maliu
Browse files

Bug 1360587 - Part 2. Remove bouncer apk build config; source; docs, r=nalexander

MozReview-Commit-ID: C1QJcr65yWu

--HG--
extra : rebase_source : 867d143416321adc4820d488991fb4575c767cf0
parent ee011aac
No related branches found
No related tags found
No related merge requests found
Showing
with 9 additions and 521 deletions
......@@ -173,9 +173,7 @@ android {
}
assets {
if (mozconfig.substs.MOZ_ANDROID_DISTRIBUTION_DIRECTORY && !mozconfig.substs.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.
if (mozconfig.substs.MOZ_ANDROID_DISTRIBUTION_DIRECTORY) {
srcDir "${mozconfig.substs.MOZ_ANDROID_DISTRIBUTION_DIRECTORY}/assets"
}
srcDir "${topsrcdir}/mobile/android/app/assets"
......
......@@ -15,11 +15,11 @@
#endif
android:targetSdkVersion="@ANDROID_TARGET_SDK@"/>
<!-- 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. -->
<!--
The separated permission file is for bouncer.apk. Since it's removed,
we can merge the permission declaration back. See Bug 1411809.
-->
#include FennecManifest_permissions.xml.in
<application android:label="@string/moz_app_displayname"
......
<!-- The bouncer APK and the Fennec 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 elements here, so that
they can be easily shared between the two APKs. -->
#include ../services/manifests/FxAccountAndroidManifest_permissions.xml.in
......@@ -23,9 +18,6 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- READ_EXTERNAL_STORAGE was added in API 16, and is only enforced in API
19+. We declare it so that the bouncer APK and the main APK have the
same set of permissions. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
......
......@@ -1413,13 +1413,9 @@ ANDROID_ASSETS_DIRS += [
]
if CONFIG['MOZ_ANDROID_DISTRIBUTION_DIRECTORY']:
# 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',
]
ANDROID_ASSETS_DIRS += [
'%' + CONFIG['MOZ_ANDROID_DISTRIBUTION_DIRECTORY'] + '/assets',
]
if CONFIG['MOZ_ANDROID_SEARCH_ACTIVITY']:
# The Search Activity is mostly independent of Fennec proper, but
......
#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="@ANDROID_TARGET_SDK@"/>
<!-- 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">
<!-- Aping org.mozilla.gecko.BrowserApp. -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER"/>
<category android:name="android.intent.category.APP_BROWSER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.sec.minimode.icon.portrait.normal"
android:resource="@drawable/icon"/>
<meta-data android:name="com.sec.minimode.icon.landscape.normal"
android:resource="@drawable/icon" />
<intent-filter>
<action android:name="android.intent.action.WEB_SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="" />
<data android:scheme="http" />
<data android:scheme="https" />
</intent-filter>
<!-- Aping org.mozilla.gecko.tabqueue.TabQueueDispatcher. -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="about" />
<data android:scheme="javascript" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:mimeType="text/html"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="application/xhtml+xml"/>
</intent-filter>
</activity>
<service
android:name="org.mozilla.bouncer.BouncerService"
android:exported="false" />
</application>
</manifest>
# 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)
# Targets built very early during a Gradle build.
gradle-targets: $(abspath AndroidManifest.xml)
.PHONY: gradle-targets
libs:: $(ANDROID_APK_NAME).apk
This is an example asset.
buildDir "${topobjdir}/gradle/build/mobile/android/bouncer"
apply plugin: 'com.android.application'
android {
compileSdkVersion project.ext.compileSdkVersion
buildToolsVersion project.ext.buildToolsVersion
defaultConfig {
targetSdkVersion project.ext.targetSdkVersion
minSdkVersion project.ext.minSdkVersion
manifestPlaceholders = project.ext.manifestPlaceholders
applicationId mozconfig.substs.ANDROID_PACKAGE_NAME
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
dexOptions {
javaMaxHeapSize "2g"
}
lintOptions {
abortOnError false
}
buildTypes {
release {
minifyEnabled false
}
}
sourceSets {
main {
manifest.srcFile "${topobjdir}/mobile/android/bouncer/AndroidManifest.xml"
assets {
if (mozconfig.substs.MOZ_ANDROID_DISTRIBUTION_DIRECTORY) {
srcDir "${mozconfig.substs.MOZ_ANDROID_DISTRIBUTION_DIRECTORY}/assets"
}
}
java {
srcDir 'java'
}
res {
srcDir "${topsrcdir}/${mozconfig.substs.MOZ_BRANDING_DIRECTORY}/res" // For the icon.
srcDir 'res'
}
}
}
}
task generateCodeAndResources(type:Exec) {
workingDir "${topobjdir}"
commandLine mozconfig.substs.GMAKE
args '-C'
args "${topobjdir}/mobile/android/bouncer"
args 'gradle-targets'
// Only show the output if something went wrong.
ignoreExitValue = true
standardOutput = new ByteArrayOutputStream()
errorOutput = standardOutput
doLast {
if (execResult.exitValue != 0) {
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
}
}
}
afterEvaluate {
android.applicationVariants.all {
preBuild.dependsOn generateCodeAndResources
}
}
/* -*- 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 File getDataFile(final String path) {
File outFile = new File(getApplicationInfo().dataDir, 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();
}
}
}
/* -*- 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();
}
}
# -*- Mode: python; 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',
'ANDROID_TARGET_SDK',
'MOZ_ANDROID_BROWSER_INTENT_CLASS',
'MOZ_APP_DISPLAYNAME',
'MOZ_APP_VERSION'):
DEFINES[var] = CONFIG[var]
for var in ('MOZ_ANDROID_GCM',
'MOZ_ANDROID_MIN_SDK_VERSION',
'MOZ_ANDROID_MAX_SDK_VERSION',
'MOZ_ANDROID_DOWNLOADS_INTEGRATION',
'MOZ_ANDROID_BEAM',
'MOZ_ANDROID_SEARCH_ACTIVITY',
'MOZ_ANDROID_MLS_STUMBLER'):
if CONFIG[var]:
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',
]
DEFINES['MOZ_ANDROID_SHARED_ID'] = CONFIG['MOZ_ANDROID_SHARED_ID']
OBJDIR_PP_FILES.mobile.android.bouncer += [
'AndroidManifest.xml.in',
]
<?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"
/>
<?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"/>
.. -*- Mode: rst; fill-column: 100; -*-
=========================================
The Firefox for Android install bouncer
=========================================
`Bug 1234629 <https://bugzilla.mozilla.org/show_bug.cgi?id=1234629>`_ and `Bug 1163082
<https://bugzilla.mozilla.org/show_bug.cgi?id=1163082>`_ combine to allow building a very small
Fennec-like "bouncer" APK that redirects (bounces) a potential Fennec user to the marketplace of
their choice -- usually the Google Play Store -- to install the real Firefox for Android application
APK.
The real APK should install seamlessly over top of the bouncer APK. Care is taken to keep the
bouncer and application APK <permission> manifest definitions identical, and to have the bouncer APK
<activity> manifest definitions look similar to the application APK <activity> manifest definitions.
In addition, the bouncer APK can carry a Fennec distribution, which it copies onto the device before
redirecting to the marketplace. The application APK recognizes the installed distribution and
customizes itself accordingly on first run.
The motivation is to allow partners to pre-install the very small bouncer APK on shipping devices
and to have a smooth path to upgrade to the full application APK, with a partner-specific
distribution in place.
Technical details
=================
To build the bouncer APK, define ``MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER``. To pack a distribution
into the bouncer APK (and *not* into the application APK), add a line like::
ac_add_options --with-android-distribution-directory=/path/to/fennec-distribution-sample
to your ``mozconfig`` file. See the `general distribution documentation on the wiki
<https://wiki.mozilla.org/Mobile/Distribution_Files>`_ for more information.
The ``distribution`` directory should end up in the ``assets/distribution`` directory of the bouncer
APK. It will be copied into ``/data/data/$ANDROID_PACKAGE_NAME/distribution`` when the bouncer
executes.
......@@ -18,7 +18,6 @@ Contents:
adjust
mma
defaultdomains
bouncer
shutdown
push
......
......@@ -7,9 +7,6 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- READ_EXTERNAL_STORAGE was added in API 16, and is only enforced in API
19+. We declare it so that the bouncer APK and the main APK have the
same set of permissions. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
......
......@@ -8,9 +8,6 @@ with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
SCHEDULES.exclusive = ['android']
with Files('bouncer/**'):
BUG_COMPONENT = ('Firefox for Android', 'Distributions')
with Files('branding/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
......@@ -72,9 +69,6 @@ DIRS += [
'fonts',
]
if CONFIG['MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER']:
DIRS += ['bouncer'] # No ordering implied with respect to base.
TEST_DIRS += [
'tests',
]
......
......@@ -100,13 +100,6 @@ option(env='MOZ_ANDROID_MOZILLA_ONLINE',
set_config('MOZ_ANDROID_MOZILLA_ONLINE',
depends_if('MOZ_ANDROID_MOZILLA_ONLINE')(lambda _: True))
option(env='MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER',
help='Build and package the install bouncer APK',
default=True)
set_config('MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER',
depends_if('MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER')(lambda _: True))
imply_option('MOZ_SOCIAL', False)
imply_option('MOZ_SERVICES_HEALTHREPORT', True)
imply_option('MOZ_ANDROID_HISTORY', True)
......
......@@ -40,11 +40,6 @@ project(':geckoview_example').projectDir = new File("${json.topsrcdir}/mobile/an
project(':omnijar').projectDir = new File("${json.topsrcdir}/mobile/android/app/omnijar")
project(':thirdparty').projectDir = new File("${json.topsrcdir}/mobile/android/thirdparty")
if (json.substs.MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER) {
include ':bouncer'
project(':bouncer').projectDir = new File("${json.topsrcdir}/mobile/android/bouncer")
}
// The Gradle instance is shared between settings.gradle and all the
// other build.gradle files (see
// http://forums.gradle.org/gradle/topics/define_extension_properties_from_settings_xml).
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment