Bug 1379833 Part 2: Display permissions dialog during extension install on Android

MozReview-Commit-ID: 721i0B0lC4n

--HG--
extra : rebase_source : 4fd65f05308b9fc085f7ca3bb88fc9195ec290a3
extra : intermediate-source : facd660f3c054d2d082bed635df5af312ec9773f
extra : source : 95aaed050f22ef61d3bedbb5b47d043d10624eeb
This commit is contained in:
Andrew Swan 2017-08-15 08:35:11 -07:00
Родитель a806967d80
Коммит a81fd94e72
10 изменённых файлов: 263 добавлений и 0 удалений

Просмотреть файл

@ -230,6 +230,8 @@ pref("extensions.compatability.locales.buildid", "0");
/* Don't let XPIProvider install distribution add-ons; we do our own thing on mobile. */
pref("extensions.installDistroAddons", false);
pref("extensions.webextPermissionPrompts", true);
// Add-on content security policies.
pref("extensions.webextensions.base-content-security-policy", "script-src 'self' https://* moz-extension: blob: filesystem: 'unsafe-eval' 'unsafe-inline'; object-src 'self' https://* moz-extension: blob: filesystem:;");
pref("extensions.webextensions.default-content-security-policy", "script-src 'self'; object-src 'self';");

Просмотреть файл

@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="64.0"
android:viewportWidth="64.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF66CC52" android:pathData="M42,62c2.2,0 4,-1.8 4,-4l0,-14.2c0,0 0.4,-3.7 2.8,-3.7c2.4,0 2.2,3.9 6.7,3.9c2.3,0 6.2,-1.2 6.2,-8.2c0,-7 -3.9,-7.9 -6.2,-7.9c-4.5,0 -4.3,3.7 -6.7,3.7c-2.4,0 -2.8,-3.8 -2.8,-3.8V22c0,-2.2 -1.8,-4 -4,-4H31.5c0,0 -3.4,-0.6 -3.4,-3c0,-2.4 3.8,-2.6 3.8,-7.1c0,-2.3 -1.3,-5.9 -8.3,-5.9s-8,3.6 -8,5.9c0,4.5 3.4,4.7 3.4,7.1c0,2.4 -3.4,3 -3.4,3H6c-2.2,0 -4,1.8 -4,4l0,7.8c0,0 -0.4,6 4.4,6c3.1,0 3.2,-4.1 7.3,-4.1c2,0 4,1.9 4,6c0,4.2 -2,6.3 -4,6.3c-4,0 -4.2,-4.1 -7.3,-4.1c-4.8,0 -4.4,5.8 -4.4,5.8L2,58c0,2.2 1.8,4 4,4H19c0,0 6.3,0.4 6.3,-4.4c0,-3.1 -4,-3.6 -4,-7.7c0,-2 2.2,-4.5 6.4,-4.5c4.2,0 6.6,2.5 6.6,4.5c0,4 -3.9,4.6 -3.9,7.7c0,4.9 6.3,4.4 6.3,4.4H42z"/>
</vector>

Просмотреть файл

@ -0,0 +1,26 @@
<?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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/doorhanger_section_padding_small"
android:paddingRight="@dimen/doorhanger_section_padding_small"
android:paddingTop="@dimen/doorhanger_section_padding_medium"
android:paddingBottom="@dimen/doorhanger_section_padding_medium">
<TextView android:id="@+id/extension_permission_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="@dimen/doorhanger_section_padding_small"
android:drawablePadding="@dimen/doorhanger_section_padding_small"/>
<TextView android:id="@+id/extension_permission_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

Просмотреть файл

@ -89,6 +89,7 @@ import org.mozilla.gecko.delegates.ScreenshotDelegate;
import org.mozilla.gecko.distribution.Distribution;
import org.mozilla.gecko.distribution.DistributionStoreCallback;
import org.mozilla.gecko.dlc.DownloadContentService;
import org.mozilla.gecko.extensions.ExtensionPermissionsHelper;
import org.mozilla.gecko.firstrun.FirstrunAnimationContainer;
import org.mozilla.gecko.gfx.DynamicToolbarAnimator;
import org.mozilla.gecko.gfx.DynamicToolbarAnimator.PinReason;
@ -315,6 +316,8 @@ public class BrowserApp extends GeckoApp
private AccountsHelper mAccountsHelper;
private ExtensionPermissionsHelper mExtensionPermissionsHelper;
// The tab to be selected on editing mode exit.
private Integer mTargetTabForEditingMode;
@ -818,6 +821,7 @@ public class BrowserApp extends GeckoApp
mSharedPreferencesHelper = new SharedPreferencesHelper(appContext);
mReadingListHelper = new ReadingListHelper(appContext, profile);
mAccountsHelper = new AccountsHelper(appContext, profile);
mExtensionPermissionsHelper = new ExtensionPermissionsHelper(this);
if (AppConstants.MOZ_ANDROID_BEAM) {
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
@ -1536,6 +1540,11 @@ public class BrowserApp extends GeckoApp
mAccountsHelper = null;
}
if (mExtensionPermissionsHelper != null) {
mExtensionPermissionsHelper.uninit();
mExtensionPermissionsHelper = null;
}
mSearchEngineManager.unregisterListeners();
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,

Просмотреть файл

@ -0,0 +1,85 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.extensions;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ResourceDrawableUtils;
import org.mozilla.gecko.R;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
public class ExtensionPermissionsHelper implements BundleEventListener {
private final Context mContext;
public ExtensionPermissionsHelper(Context context) {
mContext = context;
EventDispatcher.getInstance().registerUiThreadListener(this,
"Extension:PermissionPrompt");
}
public void uninit() {
EventDispatcher.getInstance().unregisterUiThreadListener(this,
"Extension:PermissionPrompt");
}
@Override // BundleEventListener
public void handleMessage(final String event, final GeckoBundle message,
final EventCallback callback) {
if ("Extension:PermissionPrompt".equals(event)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
final View view = LayoutInflater.from(mContext)
.inflate(R.layout.extension_permissions_dialog, null);
builder.setView(view);
final TextView headerText = (TextView) view.findViewById(R.id.extension_permission_header);
headerText.setText(message.getString("header"));
final TextView bodyText = (TextView) view.findViewById(R.id.extension_permission_body);
bodyText.setText(message.getString("message"));
builder.setPositiveButton(message.getString("acceptText"), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
callback.sendSuccess(true);
}
});
builder.setNegativeButton(message.getString("cancelText"), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
callback.sendSuccess(false);
}
});
final String iconUrl = message.getString("icon");
if ("DEFAULT".equals(iconUrl)) {
headerText.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_extension, 0, 0, 0);
} else {
ResourceDrawableUtils.getDrawable(mContext, iconUrl, new ResourceDrawableUtils.BitmapLoader() {
@Override
public void onBitmapFound(final Drawable d) {
headerText.setCompoundDrawablesWithIntrinsicBounds(d, null, null, null);
}
});
}
final AlertDialog dialog = builder.create();
dialog.show();
}
}
}

Просмотреть файл

@ -628,6 +628,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
'DynamicToolbar.java',
'EditBookmarkDialog.java',
'Experiments.java',
'extensions/ExtensionPermissionsHelper.java',
'FilePicker.java',
'FilePickerResultHandler.java',
'FindInPageBar.java',

Просмотреть файл

@ -0,0 +1,68 @@
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
"resource://gre/modules/Extension.jsm");
var ExtensionPermissions = {
// Prepare the strings needed for a permission notification.
_prepareStrings(info) {
let appName = Strings.brand.GetStringFromName("brandShortName");
let info2 = Object.assign({appName, addonName: info.addon.name}, info);
let strings = ExtensionData.formatPermissionStrings(info2, Strings.browser);
// We dump the main body of the dialog into a big android
// TextView. Build a big string with the full contents here.
let message = "";
if (strings.msgs.length > 0) {
message = [strings.listIntro, ...strings.msgs.map(s => `\u2022 ${s}`)].join("\n");
}
return {
header: strings.header || strings.text,
message,
acceptText: strings.acceptText,
cancelText: strings.cancelText,
};
},
// Prepare an icon for a permission notification
_prepareIcon(iconURL) {
// We can render pngs with ResourceDrawableUtils
if (iconURL.endsWith(".png")) {
return iconURL;
}
// If we can't render an icon, show the default
return "DEFAULT";
},
async observe(subject, topic, data) {
switch (topic) {
case "webextension-permission-prompt": {
let {target, info} = subject.wrappedJSObject;
let details = this._prepareStrings(info);
details.icon = this._prepareIcon(info.icon);
details.type = "Extension:PermissionPrompt";
let accepted = await EventDispatcher.instance.sendRequestForResult(details);
if (accepted) {
info.resolve();
} else {
info.reject();
}
break;
}
case "webextension-update-permissions":
// To be implemented in bug 1391579, just auto-approve until then
subject.wrappedJSObject.resolve();
break;
case "webextension-optional-permission-prompt":
// To be implemented in bug 1392176, just auto-approve until then
subject.wrappedJSObject.resolve(true);
break;
}
},
};

Просмотреть файл

@ -151,6 +151,10 @@ lazilyLoadedBrowserScripts.forEach(function (aScript) {
var lazilyLoadedObserverScripts = [
["MemoryObserver", ["memory-pressure", "Memory:Dump"], "chrome://browser/content/MemoryObserver.js"],
["ConsoleAPI", ["console-api-log-event"], "chrome://browser/content/ConsoleAPI.js"],
["ExtensionPermissions", ["webextension-permission-prompt",
"webextension-update-permissions",
"webextension-optional-permission-prompt"],
"chrome://browser/content/ExtensionPermissions.js"],
];
lazilyLoadedObserverScripts.forEach(function (aScript) {

Просмотреть файл

@ -60,6 +60,7 @@ chrome.jar:
#ifndef RELEASE_OR_BETA
content/WebcompatReporter.js (content/WebcompatReporter.js)
#endif
content/ExtensionPermissions.js (content/ExtensionPermissions.js)
% content branding %content/branding/

Просмотреть файл

@ -109,6 +109,69 @@ xpinstallDisabledMessageLocked=Software installation has been disabled by your s
xpinstallDisabledMessage2=Software installation is currently disabled. Press Enable and try again.
xpinstallDisabledButton=Enable
# LOCALIZATION NOTE (webextPerms.header)
# This string is used as a header in the webextension permissions dialog,
# %S is replaced with the localized name of the extension being installed.
# See https://bug1308309.bmoattachments.org/attachment.cgi?id=8814612
# for an example of the full dialog.
# Note, this string will be used as raw markup. Avoid characters like <, >, &
webextPerms.header=Add %S?
# LOCALIZATION NOTE (webextPerms.listIntro)
# This string will be followed by a list of permissions requested
# by the webextension.
webextPerms.listIntro=It requires your permission to:
webextPerms.add.label=Add
webextPerms.add.accessKey=A
webextPerms.cancel.label=Cancel
webextPerms.cancel.accessKey=C
webextPerms.description.bookmarks=Read and modify bookmarks
webextPerms.description.browserSettings=Read and modify browser settings
webextPerms.description.clipboardRead=Get data from the clipboard
webextPerms.description.clipboardWrite=Input data to the clipboard
webextPerms.description.downloads=Download files and read and modify the browsers download history
webextPerms.description.geolocation=Access your location
webextPerms.description.history=Access browsing history
webextPerms.description.management=Monitor extension usage and manage themes
# LOCALIZATION NOTE (webextPerms.description.nativeMessaging)
# %S will be replaced with the name of the application
webextPerms.description.nativeMessaging=Exchange messages with programs other than %S
webextPerms.description.notifications=Display notifications to you
webextPerms.description.privacy=Read and modify privacy settings
webextPerms.description.sessions=Access recently closed tabs
webextPerms.description.tabs=Access browser tabs
webextPerms.description.topSites=Access browsing history
webextPerms.description.unlimitedStorage=Store unlimited amount of client-side data
webextPerms.description.webNavigation=Access browser activity during navigation
webextPerms.hostDescription.allUrls=Access your data for all websites
# LOCALIZATION NOTE (webextPerms.hostDescription.wildcard)
# %S will be replaced by the DNS domain for which a webextension
# is requesting access (e.g., mozilla.org)
webextPerms.hostDescription.wildcard=Access your data for sites in the %S domain
# LOCALIZATION NOTE (webextPerms.hostDescription.tooManyWildcards):
# Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 will be replaced by an integer indicating the number of additional
# domains for which this webextension is requesting permission.
webextPerms.hostDescription.tooManyWildcards=Access your data in #1 other domain;Access your data in #1 other domains
# LOCALIZATION NOTE (webextPerms.hostDescription.oneSite)
# %S will be replaced by the DNS host name for which a webextension
# is requesting access (e.g., www.mozilla.org)
webextPerms.hostDescription.oneSite=Access your data for %S
# LOCALIZATION NOTE (webextPerms.hostDescription.tooManySites)
# Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 will be replaced by an integer indicating the number of additional
# hosts for which this webextension is requesting permission.
webextPerms.hostDescription.tooManySites=Access your data on #1 other site;Access your data on #1 other sites
# Site Identity
identity.identified.verifier=Verified by: %S
identity.identified.verified_by_you=You have added a security exception for this site