mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge fx-team to mozilla-central a=merge
This commit is contained in:
commit
6226f32485
@ -48,10 +48,10 @@
|
||||
<button id="ruleview-add-rule-button" title="&addRuleButtonTooltip;" class="devtools-button"></button>
|
||||
<button id="pseudo-class-panel-toggle" title="&togglePseudoClassPanel;" class="devtools-button"></button>
|
||||
</div>
|
||||
<div id="pseudo-class-panel" class="devtools-toolbar" hidden="true">
|
||||
<label><input id="pseudo-hover-toggle" type="checkbox" value=":hover" />:hover</label>
|
||||
<label><input id="pseudo-active-toggle" type="checkbox" value=":active" />:active</label>
|
||||
<label><input id="pseudo-focus-toggle" type="checkbox" value=":focus" />:focus</label>
|
||||
<div id="pseudo-class-panel" class="devtools-toolbar" hidden="true" tabindex="-1">
|
||||
<label><input id="pseudo-hover-toggle" type="checkbox" value=":hover" tabindex="-1" />:hover</label>
|
||||
<label><input id="pseudo-active-toggle" type="checkbox" value=":active" tabindex="-1" />:active</label>
|
||||
<label><input id="pseudo-focus-toggle" type="checkbox" value=":focus" tabindex="-1" />:focus</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -2298,9 +2298,16 @@ CssRuleView.prototype = {
|
||||
_onTogglePseudoClassPanel: function() {
|
||||
if (this.pseudoClassPanel.hidden) {
|
||||
this.pseudoClassToggle.setAttribute("checked", "true");
|
||||
this.hoverCheckbox.setAttribute("tabindex", "0");
|
||||
this.activeCheckbox.setAttribute("tabindex", "0");
|
||||
this.focusCheckbox.setAttribute("tabindex", "0");
|
||||
} else {
|
||||
this.pseudoClassToggle.removeAttribute("checked");
|
||||
this.hoverCheckbox.setAttribute("tabindex", "-1");
|
||||
this.activeCheckbox.setAttribute("tabindex", "-1");
|
||||
this.focusCheckbox.setAttribute("tabindex", "-1");
|
||||
}
|
||||
|
||||
this.pseudoClassPanel.hidden = !this.pseudoClassPanel.hidden;
|
||||
},
|
||||
|
||||
|
@ -29,40 +29,38 @@ add_task(function*() {
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("div", inspector);
|
||||
|
||||
yield assertPseudoPanelClosed(view);
|
||||
|
||||
info("Toggle the pseudo class panel open");
|
||||
ok(view.pseudoClassPanel.hidden, "Pseudo Class Panel Hidden");
|
||||
view.pseudoClassToggle.click();
|
||||
ok(!view.pseudoClassPanel.hidden, "Pseudo Class Panel Opened");
|
||||
ok(!view.hoverCheckbox.disabled, ":hover checkbox is not disabled");
|
||||
ok(!view.activeCheckbox.disabled, ":active checkbox is not disabled");
|
||||
ok(!view.focusCheckbox.disabled, ":focus checkbox is not disabled");
|
||||
yield assertPseudoPanelOpened(view);
|
||||
|
||||
info("Toggle each pseudo lock and check that the pseudo lock is added");
|
||||
yield togglePseudoClass(inspector, view, view.hoverCheckbox);
|
||||
yield togglePseudoClass(inspector, view.hoverCheckbox);
|
||||
yield assertPseudoAdded(inspector, view, ":hover", 3, 1);
|
||||
yield togglePseudoClass(inspector, view, view.hoverCheckbox);
|
||||
yield togglePseudoClass(inspector, view.hoverCheckbox);
|
||||
yield assertPseudoRemoved(inspector, view, 2);
|
||||
|
||||
yield togglePseudoClass(inspector, view, view.activeCheckbox);
|
||||
yield togglePseudoClass(inspector, view.activeCheckbox);
|
||||
yield assertPseudoAdded(inspector, view, ":active", 3, 1);
|
||||
yield togglePseudoClass(inspector, view, view.activeCheckbox);
|
||||
yield togglePseudoClass(inspector, view.activeCheckbox);
|
||||
yield assertPseudoRemoved(inspector, view, 2);
|
||||
|
||||
yield togglePseudoClass(inspector, view, view.focusCheckbox);
|
||||
yield togglePseudoClass(inspector, view.focusCheckbox);
|
||||
yield assertPseudoAdded(inspector, view, ":focus", 3, 1);
|
||||
yield togglePseudoClass(inspector, view, view.focusCheckbox);
|
||||
yield togglePseudoClass(inspector, view.focusCheckbox);
|
||||
yield assertPseudoRemoved(inspector, view, 2);
|
||||
|
||||
info("Toggle all pseudo lock and check that the pseudo lock is added");
|
||||
yield togglePseudoClass(inspector, view, view.hoverCheckbox);
|
||||
yield togglePseudoClass(inspector, view, view.activeCheckbox);
|
||||
yield togglePseudoClass(inspector, view, view.focusCheckbox);
|
||||
yield togglePseudoClass(inspector, view.hoverCheckbox);
|
||||
yield togglePseudoClass(inspector, view.activeCheckbox);
|
||||
yield togglePseudoClass(inspector, view.focusCheckbox);
|
||||
yield assertPseudoAdded(inspector, view, ":focus", 5, 1);
|
||||
yield assertPseudoAdded(inspector, view, ":active", 5, 2);
|
||||
yield assertPseudoAdded(inspector, view, ":hover", 5, 3);
|
||||
yield togglePseudoClass(inspector, view, view.hoverCheckbox);
|
||||
yield togglePseudoClass(inspector, view, view.activeCheckbox);
|
||||
yield togglePseudoClass(inspector, view, view.focusCheckbox);
|
||||
yield togglePseudoClass(inspector, view.hoverCheckbox);
|
||||
yield togglePseudoClass(inspector, view.activeCheckbox);
|
||||
yield togglePseudoClass(inspector, view.focusCheckbox);
|
||||
yield assertPseudoRemoved(inspector, view, 2);
|
||||
|
||||
info("Select a null element");
|
||||
@ -76,29 +74,62 @@ add_task(function*() {
|
||||
|
||||
info("Toggle the pseudo class panel close");
|
||||
view.pseudoClassToggle.click();
|
||||
ok(view.pseudoClassPanel.hidden, "Pseudo Class Panel Closed");
|
||||
yield assertPseudoPanelClosed(view);
|
||||
});
|
||||
|
||||
function* togglePseudoClass(inspector, ruleView, pseudoClassOption) {
|
||||
function* togglePseudoClass(inspector, pseudoClassOption) {
|
||||
info("Toggle the pseudoclass, wait for it to be applied");
|
||||
let onRefresh = inspector.once("rule-view-refreshed");
|
||||
pseudoClassOption.click();
|
||||
yield onRefresh;
|
||||
}
|
||||
|
||||
function* assertPseudoAdded(inspector, ruleView, pseudoClass, numRules,
|
||||
function* assertPseudoAdded(inspector, view, pseudoClass, numRules,
|
||||
childIndex) {
|
||||
info("Check that the ruleview contains the pseudo-class rule");
|
||||
is(ruleView.element.children.length, numRules,
|
||||
is(view.element.children.length, numRules,
|
||||
"Should have " + numRules + " rules.");
|
||||
is(getRuleViewRuleEditor(ruleView, childIndex).rule.selectorText,
|
||||
is(getRuleViewRuleEditor(view, childIndex).rule.selectorText,
|
||||
"div" + pseudoClass, "rule view is showing " + pseudoClass + " rule");
|
||||
}
|
||||
|
||||
function* assertPseudoRemoved(inspector, ruleView, numRules) {
|
||||
function* assertPseudoRemoved(inspector, view, numRules) {
|
||||
info("Check that the ruleview no longer contains the pseudo-class rule");
|
||||
is(ruleView.element.children.length, numRules,
|
||||
is(view.element.children.length, numRules,
|
||||
"Should have " + numRules + " rules.");
|
||||
is(getRuleViewRuleEditor(ruleView, 1).rule.selectorText, "div",
|
||||
is(getRuleViewRuleEditor(view, 1).rule.selectorText, "div",
|
||||
"Second rule is div");
|
||||
}
|
||||
|
||||
function* assertPseudoPanelOpened(view) {
|
||||
info("Check the opened state of the pseudo class panel");
|
||||
|
||||
ok(!view.pseudoClassPanel.hidden, "Pseudo Class Panel Opened");
|
||||
ok(!view.hoverCheckbox.disabled, ":hover checkbox is not disabled");
|
||||
ok(!view.activeCheckbox.disabled, ":active checkbox is not disabled");
|
||||
ok(!view.focusCheckbox.disabled, ":focus checkbox is not disabled");
|
||||
|
||||
is(view.pseudoClassPanel.getAttribute("tabindex"), "-1",
|
||||
"Pseudo Class Panel has a tabindex of -1");
|
||||
is(view.hoverCheckbox.getAttribute("tabindex"), "0",
|
||||
":hover checkbox has a tabindex of 0");
|
||||
is(view.activeCheckbox.getAttribute("tabindex"), "0",
|
||||
":active checkbox has a tabindex of 0");
|
||||
is(view.focusCheckbox.getAttribute("tabindex"), "0",
|
||||
":focus checkbox has a tabindex of 0");
|
||||
}
|
||||
|
||||
function* assertPseudoPanelClosed(view) {
|
||||
info("Check the closed state of the pseudo clas panel");
|
||||
|
||||
ok(view.pseudoClassPanel.hidden, "Pseudo Class Panel Hidden");
|
||||
|
||||
is(view.pseudoClassPanel.getAttribute("tabindex"), "-1",
|
||||
"Pseudo Class Panel has a tabindex of -1");
|
||||
is(view.hoverCheckbox.getAttribute("tabindex"), "-1",
|
||||
":hover checkbox has a tabindex of -1");
|
||||
is(view.activeCheckbox.getAttribute("tabindex"), "-1",
|
||||
":active checkbox has a tabindex of -1");
|
||||
is(view.focusCheckbox.getAttribute("tabindex"), "-1",
|
||||
":focus checkbox has a tabindex of -1");
|
||||
}
|
||||
|
@ -309,7 +309,7 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="org.mozilla.gecko.RestrictionProvider">
|
||||
<receiver android:name="org.mozilla.gecko.restrictions.RestrictionProvider">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
|
||||
</intent-filter>
|
||||
|
@ -55,6 +55,7 @@ import org.mozilla.gecko.preferences.ClearOnShutdownPref;
|
||||
import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
import org.mozilla.gecko.prompts.Prompt;
|
||||
import org.mozilla.gecko.prompts.PromptListItem;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
@ -1975,7 +1976,7 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED) {
|
||||
if (AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED && RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_LOCATION_SERVICE)) {
|
||||
// Start (this acts as ping if started already) the stumbler lib; if the stumbler has queued data it will upload it.
|
||||
// Stumbler operates on its own thread, and startup impact is further minimized by delaying work (such as upload) a few seconds.
|
||||
// Avoid any potential startup CPU/thread contention by delaying the pref broadcast.
|
||||
@ -2634,6 +2635,10 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
|
||||
private void showFirstrunPager() {
|
||||
// Do not show first run if we're in an Android Restricted Profile
|
||||
if (RestrictedProfiles.isUserRestricted(this)) {
|
||||
return;
|
||||
}
|
||||
if (mFirstrunPane == null) {
|
||||
final ViewStub firstrunPagerStub = (ViewStub) findViewById(R.id.firstrun_pager_stub);
|
||||
mFirstrunPane = (FirstrunPane) firstrunPagerStub.inflate();
|
||||
@ -2690,7 +2695,7 @@ public class BrowserApp extends GeckoApp
|
||||
});
|
||||
|
||||
// Don't show the banner in guest mode.
|
||||
if (!getProfile().inGuestMode()) {
|
||||
if (!RestrictedProfiles.isUserRestricted()) {
|
||||
final ViewStub homeBannerStub = (ViewStub) findViewById(R.id.home_banner_stub);
|
||||
final HomeBanner homeBanner = (HomeBanner) homeBannerStub.inflate();
|
||||
mHomePager.setBanner(homeBanner);
|
||||
@ -3286,12 +3291,12 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
|
||||
// Disable share menuitem for about:, chrome:, file:, and resource: URIs
|
||||
final boolean shareVisible = RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_SHARE);
|
||||
final boolean shareVisible = RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_SHARE);
|
||||
share.setVisible(shareVisible);
|
||||
final boolean shareEnabled = StringUtils.isShareableUrl(url) && shareVisible;
|
||||
share.setEnabled(shareEnabled);
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_INSTALL_EXTENSION));
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.downloads, RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_DOWNLOADS));
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_INSTALL_EXTENSION));
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.downloads, RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_DOWNLOADS));
|
||||
|
||||
// NOTE: Use MenuUtils.safeSetEnabled because some actions might
|
||||
// be on the BrowserToolbar context menu.
|
||||
@ -3356,9 +3361,12 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
|
||||
// Hide tools menu if restriction is active
|
||||
final boolean toolsVisible = RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_TOOLS_MENU);
|
||||
final boolean toolsVisible = RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_TOOLS_MENU);
|
||||
MenuUtils.safeSetVisible(aMenu, R.id.tools, toolsVisible);
|
||||
|
||||
final boolean privateTabVisible = RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_PRIVATE_BROWSING);
|
||||
MenuUtils.safeSetVisible(aMenu, R.id.new_private_tab, privateTabVisible);
|
||||
|
||||
// Disable save as PDF for about:home and xul pages.
|
||||
saveAsPDF.setEnabled(!(isAboutHome(tab) ||
|
||||
tab.getContentType().equals("application/vnd.mozilla.xul+xml") ||
|
||||
|
@ -1209,12 +1209,6 @@ public class GeckoAppShell
|
||||
final Intent intent = getOpenURIIntentInner(context, targetURI, mimeType, action, title);
|
||||
|
||||
if (intent != null) {
|
||||
// Setting category on file:// URIs breaks about:downloads (Bug 1176018)
|
||||
if (!targetURI.startsWith("file:")) {
|
||||
// Only handle applications which can accept arbitrary data from a browser.
|
||||
intent.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||
}
|
||||
|
||||
// Some applications use this field to return to the same browser after processing the
|
||||
// Intent. While there is some danger (e.g. denial of service), other major browsers already
|
||||
// use it and so it's the norm.
|
||||
@ -1245,15 +1239,18 @@ public class GeckoAppShell
|
||||
}
|
||||
|
||||
final String scheme = uri.getScheme();
|
||||
if ("intent".equals(scheme)) {
|
||||
if ("intent".equals(scheme) || "android-app".equals(scheme)) {
|
||||
final Intent intent;
|
||||
try {
|
||||
intent = Intent.parseUri(targetURI, Intent.URI_INTENT_SCHEME);
|
||||
intent = Intent.parseUri(targetURI, 0);
|
||||
} catch (final URISyntaxException e) {
|
||||
Log.e(LOGTAG, "Unable to parse URI - " + e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Only open applications which can accept arbitrary data from a browser.
|
||||
intent.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||
|
||||
// Prevent site from explicitly opening our internal activities, which can leak data.
|
||||
intent.setComponent(null);
|
||||
nullIntentSelector(intent);
|
||||
|
@ -5,18 +5,17 @@
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.mozglue.RobocopTarget;
|
||||
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
|
||||
import org.mozilla.gecko.restrictions.DefaultConfiguration;
|
||||
import org.mozilla.gecko.restrictions.GuestProfileConfiguration;
|
||||
import org.mozilla.gecko.restrictions.RestrictedProfileConfiguration;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
import org.mozilla.gecko.restrictions.RestrictionConfiguration;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
@ -26,118 +25,55 @@ import android.util.Log;
|
||||
public class RestrictedProfiles {
|
||||
private static final String LOGTAG = "GeckoRestrictedProfiles";
|
||||
|
||||
private static volatile Boolean inGuest = null;
|
||||
private static RestrictionConfiguration configuration;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static final List<String> BANNED_SCHEMES = new ArrayList<String>() {{
|
||||
add("file");
|
||||
add("chrome");
|
||||
add("resource");
|
||||
add("jar");
|
||||
add("wyciwyg");
|
||||
}};
|
||||
|
||||
private static final String ABOUT_ADDONS = "about:addons";
|
||||
|
||||
/**
|
||||
* This is a hack to allow non-GeckoApp activities to safely call into
|
||||
* RestrictedProfiles without reworking this class or GeckoProfile.
|
||||
*
|
||||
* It can be removed after Bug 1077590 lands.
|
||||
*/
|
||||
public static void initWithProfile(GeckoProfile profile) {
|
||||
inGuest = profile.inGuestMode();
|
||||
}
|
||||
|
||||
private static boolean getInGuest() {
|
||||
if (inGuest == null) {
|
||||
inGuest = GeckoAppShell.getGeckoInterface().getProfile().inGuestMode();
|
||||
private static RestrictionConfiguration getConfiguration(Context context) {
|
||||
if (configuration == null) {
|
||||
configuration = createConfiguration(context);
|
||||
}
|
||||
|
||||
return inGuest;
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static final List<String> BANNED_URLS = new ArrayList<String>() {{
|
||||
add("about:config");
|
||||
}};
|
||||
|
||||
/* This is a list of things we can restrict you from doing. Some of these are reflected in Android UserManager constants.
|
||||
* Others are specific to us.
|
||||
* These constants should be in sync with the ones from toolkit/components/parentalcontrols/nsIParentalControlServices.idl
|
||||
*/
|
||||
public enum Restriction {
|
||||
// These restrictions have no strings assigned because they are only used in guest mode and not shown in the
|
||||
// restricted profiles settings UI
|
||||
DISALLOW_DOWNLOADS(1, "no_download_files", 0, 0),
|
||||
DISALLOW_BROWSE_FILES(4, "no_browse_files", 0, 0),
|
||||
DISALLOW_SHARE(5, "no_share", 0, 0),
|
||||
DISALLOW_BOOKMARK(6, "no_bookmark", 0, 0),
|
||||
DISALLOW_ADD_CONTACTS(7, "no_add_contacts", 0, 0),
|
||||
DISALLOW_SET_IMAGE(8, "no_set_image", 0, 0),
|
||||
DISALLOW_MODIFY_ACCOUNTS(9, "no_modify_accounts", 0, 0), // UserManager.DISALLOW_MODIFY_ACCOUNTS
|
||||
DISALLOW_REMOTE_DEBUGGING(10, "no_remote_debugging", 0, 0),
|
||||
|
||||
// These restrictions are used for restricted profiles and therefore need to have strings assigned for the profile
|
||||
// settings UI.
|
||||
DISALLOW_INSTALL_EXTENSION(2, "no_install_extensions", R.string.restriction_disallow_addons_title, R.string.restriction_disallow_addons_description),
|
||||
DISALLOW_INSTALL_APPS(3, "no_install_apps", R.string.restriction_disallow_apps_title, R.string.restriction_disallow_apps_description), // UserManager.DISALLOW_INSTALL_APPS
|
||||
DISALLOW_IMPORT_SETTINGS(11, "no_report_site_issue", R.string.restriction_disallow_import_settings_title, R.string.restriction_disallow_import_settings_description),
|
||||
DISALLOW_TOOLS_MENU(12, "no_tools_menu", R.string.restriction_disallow_tools_menu_title, R.string.restriction_disallow_tools_menu_description),
|
||||
DISALLOW_REPORT_SITE_ISSUE(13, "no_report_site_issue", R.string.restriction_disallow_report_site_issue_title, R.string.restriction_disallow_report_site_issue_description);
|
||||
|
||||
public final int id;
|
||||
public final String name;
|
||||
public final int titleResource;
|
||||
public final int descriptionResource;
|
||||
|
||||
Restriction(final int id, final String name, int titleResource, int descriptionResource) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.titleResource = titleResource;
|
||||
this.descriptionResource = descriptionResource;
|
||||
public static synchronized RestrictionConfiguration createConfiguration(Context context) {
|
||||
if (configuration != null) {
|
||||
// This method is synchronized and another thread might already have created the configuration.
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public String getTitle(Context context) {
|
||||
if (titleResource == 0) {
|
||||
return toString();
|
||||
if (isGuestProfile()) {
|
||||
return new GuestProfileConfiguration();
|
||||
} else if(isRestrictedProfile(context)) {
|
||||
return new RestrictedProfileConfiguration(context);
|
||||
} else {
|
||||
return new DefaultConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isGuestProfile() {
|
||||
return GeckoAppShell.getGeckoInterface().getProfile().inGuestMode();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
private static boolean isRestrictedProfile(Context context) {
|
||||
if (Versions.preJBMR2) {
|
||||
// Early versions don't support restrictions at all
|
||||
return false;
|
||||
}
|
||||
|
||||
final UserManager mgr = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
Bundle restrictions = mgr.getApplicationRestrictions(context.getPackageName());
|
||||
|
||||
for (String key : restrictions.keySet()) {
|
||||
if (restrictions.getBoolean(key)) {
|
||||
// At least one restriction is enabled -> We are a restricted profile
|
||||
return true;
|
||||
}
|
||||
|
||||
return context.getResources().getString(titleResource);
|
||||
}
|
||||
|
||||
public String getDescription(Context context) {
|
||||
if (descriptionResource == 0) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return context.getResources().getString(descriptionResource);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static List<Restriction> GUEST_RESTRICTIONS = Arrays.asList(
|
||||
Restriction.DISALLOW_DOWNLOADS,
|
||||
Restriction.DISALLOW_INSTALL_EXTENSION,
|
||||
Restriction.DISALLOW_INSTALL_APPS,
|
||||
Restriction.DISALLOW_BROWSE_FILES,
|
||||
Restriction.DISALLOW_SHARE,
|
||||
Restriction.DISALLOW_BOOKMARK,
|
||||
Restriction.DISALLOW_ADD_CONTACTS,
|
||||
Restriction.DISALLOW_SET_IMAGE,
|
||||
Restriction.DISALLOW_MODIFY_ACCOUNTS,
|
||||
Restriction.DISALLOW_REMOTE_DEBUGGING,
|
||||
Restriction.DISALLOW_IMPORT_SETTINGS
|
||||
);
|
||||
|
||||
// Restricted profiles will automatically have these restrictions by default
|
||||
static List<Restriction> RESTRICTED_PROFILE_RESTRICTIONS = Arrays.asList(
|
||||
Restriction.DISALLOW_INSTALL_EXTENSION,
|
||||
Restriction.DISALLOW_INSTALL_APPS,
|
||||
Restriction.DISALLOW_TOOLS_MENU,
|
||||
Restriction.DISALLOW_REPORT_SITE_ISSUE,
|
||||
Restriction.DISALLOW_IMPORT_SETTINGS
|
||||
);
|
||||
|
||||
private static Restriction geckoActionToRestriction(int action) {
|
||||
for (Restriction rest : Restriction.values()) {
|
||||
if (rest.id == action) {
|
||||
@ -148,71 +84,8 @@ public class RestrictedProfiles {
|
||||
throw new IllegalArgumentException("Unknown action " + action);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
private static Bundle getRestrictions(final Context context) {
|
||||
final UserManager mgr = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
return mgr.getUserRestrictions();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
private static Bundle getAppRestrictions(final Context context) {
|
||||
final UserManager mgr = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
return mgr.getApplicationRestrictions(context.getPackageName());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does the system version check for you.
|
||||
*
|
||||
* Returns false if the system doesn't support restrictions,
|
||||
* or the provided value is not present in the set of user
|
||||
* restrictions.
|
||||
*
|
||||
* Returns true otherwise.
|
||||
*/
|
||||
private static boolean getRestriction(final Context context, final Restriction restriction) {
|
||||
// Early versions don't support restrictions at all,
|
||||
// so no action can be restricted.
|
||||
if (Versions.preJBMR2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isUserRestricted(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return getAppRestrictions(context).getBoolean(restriction.name, RESTRICTED_PROFILE_RESTRICTIONS.contains(restriction));
|
||||
}
|
||||
|
||||
private static boolean canLoadUrl(final Context context, final String url) {
|
||||
// Null URLs are always permitted.
|
||||
if (url == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
// If we're not in guest mode, and the system restriction isn't in place, everything is allowed.
|
||||
if (!getInGuest() &&
|
||||
!getRestriction(context, Restriction.DISALLOW_BROWSE_FILES)) {
|
||||
return true;
|
||||
}
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Log.i(LOGTAG, "Invalid action", ex);
|
||||
}
|
||||
|
||||
final Uri u = Uri.parse(url);
|
||||
final String scheme = u.getScheme();
|
||||
if (BANNED_SCHEMES.contains(scheme)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String banned : BANNED_URLS) {
|
||||
if (url.startsWith(banned)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The UserManager should support blacklisting URLs by the device owner.
|
||||
return true;
|
||||
return getConfiguration(context).canLoadUrl(url);
|
||||
}
|
||||
|
||||
@WrapElementForJNI
|
||||
@ -221,36 +94,15 @@ public class RestrictedProfiles {
|
||||
}
|
||||
|
||||
public static boolean isUserRestricted(final Context context) {
|
||||
// Guest mode is supported in all Android versions.
|
||||
if (getInGuest()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Versions.preJBMR2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Bundle restrictions = getRestrictions(context);
|
||||
for (String key : restrictions.keySet()) {
|
||||
if (restrictions.getBoolean(key)) {
|
||||
// At least one restriction is enabled -> We are a restricted profile
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return getConfiguration(context).isRestricted();
|
||||
}
|
||||
|
||||
public static boolean isAllowed(final Context context, final Restriction action) {
|
||||
return isAllowed(context, action, null);
|
||||
public static boolean isAllowed(final Context context, final Restriction restriction) {
|
||||
return getConfiguration(context).isAllowed(restriction);
|
||||
}
|
||||
|
||||
@WrapElementForJNI
|
||||
public static boolean isAllowed(int action, String url) {
|
||||
return isAllowed(GeckoAppShell.getContext(), action, url);
|
||||
}
|
||||
|
||||
private static boolean isAllowed(final Context context, int action, String url) {
|
||||
final Restriction restriction;
|
||||
try {
|
||||
restriction = geckoActionToRestriction(action);
|
||||
@ -261,62 +113,12 @@ public class RestrictedProfiles {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isAllowed(context, restriction, url);
|
||||
}
|
||||
final Context context = GeckoAppShell.getContext();
|
||||
|
||||
private static boolean isAllowed(final Context context, final Restriction restriction, String url) {
|
||||
if (getInGuest()) {
|
||||
if (Restriction.DISALLOW_BROWSE_FILES == restriction) {
|
||||
return canLoadUrl(context, url);
|
||||
}
|
||||
|
||||
return !GUEST_RESTRICTIONS.contains(restriction);
|
||||
if (Restriction.DISALLOW_BROWSE_FILES == restriction) {
|
||||
return canLoadUrl(context, url);
|
||||
} else {
|
||||
return isAllowed(context, restriction);
|
||||
}
|
||||
|
||||
// Disallow browsing about:addons if 'disallow install extension' restriction is enforced
|
||||
if (restriction == Restriction.DISALLOW_BROWSE_FILES
|
||||
&& url.toLowerCase().startsWith(ABOUT_ADDONS)
|
||||
&& !isAllowed(context, Restriction.DISALLOW_INSTALL_EXTENSION)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Restrictions hold the opposite intention, so we need to flip it.
|
||||
return !getRestriction(context, restriction);
|
||||
}
|
||||
|
||||
@WrapElementForJNI
|
||||
public static String getUserRestrictions() {
|
||||
return getUserRestrictions(GeckoAppShell.getContext());
|
||||
}
|
||||
|
||||
private static String getUserRestrictions(final Context context) {
|
||||
// Guest mode is supported in all Android versions
|
||||
if (getInGuest()) {
|
||||
StringBuilder builder = new StringBuilder("{ ");
|
||||
|
||||
for (Restriction restriction : Restriction.values()) {
|
||||
builder.append("\"" + restriction.name + "\": true, ");
|
||||
}
|
||||
|
||||
builder.append(" }");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
if (Versions.preJBMR2) {
|
||||
return "{}";
|
||||
}
|
||||
|
||||
final JSONObject json = new JSONObject();
|
||||
final Bundle restrictions = getRestrictions(context);
|
||||
final Set<String> keys = restrictions.keySet();
|
||||
|
||||
for (String key : keys) {
|
||||
try {
|
||||
json.put(key, restrictions.get(key));
|
||||
} catch (JSONException e) {
|
||||
}
|
||||
}
|
||||
|
||||
return json.toString();
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import org.mozilla.gecko.home.HomeConfig.OnReloadListener;
|
||||
import org.mozilla.gecko.home.HomeConfig.PanelConfig;
|
||||
import org.mozilla.gecko.home.HomeConfig.PanelType;
|
||||
import org.mozilla.gecko.home.HomeConfig.State;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
@ -80,7 +81,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
|
||||
|
||||
// We disable Synced Tabs for guest mode profiles.
|
||||
final PanelConfig remoteTabsEntry;
|
||||
if (RestrictedProfiles.isAllowed(mContext, RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
|
||||
if (RestrictedProfiles.isAllowed(mContext, Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
|
||||
remoteTabsEntry = createBuiltinPanelConfig(mContext, PanelType.REMOTE_TABS);
|
||||
} else {
|
||||
remoteTabsEntry = null;
|
||||
|
@ -7,14 +7,13 @@ package org.mozilla.gecko.home;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.EditBookmarkDialog;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.ReaderModeUtils;
|
||||
import org.mozilla.gecko.RestrictedProfiles;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
@ -24,6 +23,7 @@ import org.mozilla.gecko.home.HomeContextMenuInfo.RemoveItemType;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.TopSitesGridView.TopSitesGridContextMenuInfo;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
@ -151,6 +151,10 @@ public abstract class HomeFragment extends Fragment {
|
||||
if (!StringUtils.isShareableUrl(info.url) || GeckoProfile.get(getActivity()).inGuestMode()) {
|
||||
menu.findItem(R.id.home_share).setVisible(false);
|
||||
}
|
||||
|
||||
if (!RestrictedProfiles.isAllowed(view.getContext(), Restriction.DISALLOW_PRIVATE_BROWSING)) {
|
||||
menu.findItem(R.id.home_open_private_tab).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,9 +5,11 @@ import android.database.Cursor;
|
||||
import android.database.DataSetObserver;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewStub;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
@ -197,6 +199,10 @@ public class RemoteTabsSplitPlaneFragment extends RemoteTabsBaseFragment {
|
||||
// Now the adapter is wrapped; we can remove our footer view.
|
||||
mClientList.removeFooterView(mFooterView);
|
||||
|
||||
// Register touch handler to conditionally enable swipe refresh layout.
|
||||
mClientList.setOnTouchListener(new ListTouchListener(mClientList));
|
||||
mTabList.setOnTouchListener(new ListTouchListener(mTabList));
|
||||
|
||||
// Create callbacks before the initial loader is started
|
||||
mCursorLoaderCallbacks = new CursorLoaderCallbacks();
|
||||
loadIfVisible();
|
||||
@ -362,4 +368,35 @@ public class RemoteTabsSplitPlaneFragment extends RemoteTabsBaseFragment {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OnTouchListener implementation for ListView that enables swipe to refresh on the touch down event iff list cannot scroll up.
|
||||
* This implementation does not consume the <code>MotionEvent</code>.
|
||||
*/
|
||||
private class ListTouchListener implements View.OnTouchListener {
|
||||
private final AbsListView listView;
|
||||
|
||||
public ListTouchListener(AbsListView listView) {
|
||||
this.listView = listView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
final int action = event.getAction();
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Enable swipe to refresh iff the first item is visible and is at the top.
|
||||
mRefreshLayout.setEnabled(listView.getCount() <= 0
|
||||
|| (listView.getFirstVisiblePosition() <= 0 && listView.getChildAt(0).getTop() >= 0));
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
mRefreshLayout.setEnabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
// Event is not handled here, it will be consumed in enclosing SwipeRefreshLayout.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import java.util.Map;
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.Locales;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.RestrictedProfiles;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
@ -33,6 +34,7 @@ import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.PinSiteDialog.OnSiteSelectedListener;
|
||||
import org.mozilla.gecko.home.TopSitesGridView.OnEditPinnedSiteListener;
|
||||
import org.mozilla.gecko.home.TopSitesGridView.TopSitesGridContextMenuInfo;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
import org.mozilla.gecko.tiles.TilesRecorder;
|
||||
import org.mozilla.gecko.tiles.Tile;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
@ -369,6 +371,10 @@ public class TopSitesPanel extends HomeFragment {
|
||||
if (!StringUtils.isShareableUrl(info.url) || GeckoProfile.get(getActivity()).inGuestMode()) {
|
||||
menu.findItem(R.id.home_share).setVisible(false);
|
||||
}
|
||||
|
||||
if (!RestrictedProfiles.isAllowed(view.getContext(), Restriction.DISALLOW_PRIVATE_BROWSING)) {
|
||||
menu.findItem(R.id.home_open_private_tab).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -693,4 +693,11 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
||||
<!ENTITY restriction_disallow_addons_description "Disallow installation of add-ons.">
|
||||
<!ENTITY restriction_disallow_apps_title "Disallow apps">
|
||||
<!ENTITY restriction_disallow_apps_description "Disallow installing apps from Firefox Marketplace.">
|
||||
|
||||
<!ENTITY restriction_disallow_devtools_title "Disallow developer tools">
|
||||
<!ENTITY restriction_disallow_devtools_description "Disallow usage of developer tools.">
|
||||
<!ENTITY restriction_disallow_customize_home_title "Disallow customizing home">
|
||||
<!ENTITY restriction_disallow_customize_home_description "Disallow customizing home panels.">
|
||||
<!ENTITY restriction_disallow_private_browsing_title "Disallow private browsing">
|
||||
<!ENTITY restriction_disallow_private_browsing_description "Disallow private browsing mode.">
|
||||
<!ENTITY restriction_disallow_location_services_title "Disallow location services">
|
||||
<!ENTITY restriction_disallow_location_services_description "Disallow sharing of location data to improve geolocation service.">
|
||||
|
@ -434,7 +434,12 @@ gbjar.sources += [
|
||||
'RemoteTabsExpandableListAdapter.java',
|
||||
'Restarter.java',
|
||||
'RestrictedProfiles.java',
|
||||
'RestrictionProvider.java',
|
||||
'restrictions/DefaultConfiguration.java',
|
||||
'restrictions/GuestProfileConfiguration.java',
|
||||
'restrictions/RestrictedProfileConfiguration.java',
|
||||
'restrictions/Restriction.java',
|
||||
'restrictions/RestrictionConfiguration.java',
|
||||
'restrictions/RestrictionProvider.java',
|
||||
'ServiceNotificationClient.java',
|
||||
'SessionParser.java',
|
||||
'SharedPreferencesHelper.java',
|
||||
|
@ -9,7 +9,7 @@ import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.RestrictedProfiles;
|
||||
import org.mozilla.gecko.RestrictedProfiles.Restriction;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -7,6 +7,7 @@ package org.mozilla.gecko.preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -37,6 +38,7 @@ import org.mozilla.gecko.TelemetryContract.Method;
|
||||
import org.mozilla.gecko.background.common.GlobalConstants;
|
||||
import org.mozilla.gecko.background.healthreport.HealthReportConstants;
|
||||
import org.mozilla.gecko.db.BrowserContract.SuggestedSites;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
import org.mozilla.gecko.updater.UpdateService;
|
||||
import org.mozilla.gecko.updater.UpdateServiceHelper;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
@ -130,6 +132,9 @@ OnSharedPreferenceChangeListener
|
||||
public static final String PREFS_VOICE_INPUT_ENABLED = NON_PREF_PREFIX + "voice_input_enabled";
|
||||
public static final String PREFS_QRCODE_ENABLED = NON_PREF_PREFIX + "qrcode_enabled";
|
||||
private static final String PREFS_DEVTOOLS = NON_PREF_PREFIX + "devtools.enabled";
|
||||
private static final String PREFS_CUSTOMIZE_HOME = NON_PREF_PREFIX + "customize_home";
|
||||
private static final String PREFS_TRACKING_PROTECTION_PRIVATE_BROWSING = "privacy.trackingprotection.pbmode.enabled";
|
||||
private static final String PREFS_TRACKING_PROTECTION_LEARN_MORE = NON_PREF_PREFIX + "trackingprotection.learn_more";
|
||||
|
||||
private static final String ACTION_STUMBLER_UPLOAD_PREF = AppConstants.ANDROID_PACKAGE_NAME + ".STUMBLER_PREF";
|
||||
|
||||
@ -309,9 +314,6 @@ OnSharedPreferenceChangeListener
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
// Make sure RestrictedProfiles is ready.
|
||||
RestrictedProfiles.initWithProfile(GeckoProfile.get(this));
|
||||
|
||||
// Apply the current user-selected locale, if necessary.
|
||||
checkLocale();
|
||||
|
||||
@ -477,15 +479,18 @@ OnSharedPreferenceChangeListener
|
||||
if (onIsMultiPane()) {
|
||||
loadHeadersFromResource(R.xml.preference_headers, target);
|
||||
|
||||
// If locale switching is disabled, remove the section
|
||||
// entirely. This logic will need to be extended when
|
||||
// content language selection (Bug 881510) is implemented.
|
||||
if (!localeSwitchingIsEnabled) {
|
||||
for (Header header : target) {
|
||||
if (header.id == R.id.pref_header_language) {
|
||||
target.remove(header);
|
||||
break;
|
||||
}
|
||||
Iterator<Header> iterator = target.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Header header = iterator.next();
|
||||
|
||||
if (header.id == R.id.pref_header_language && !localeSwitchingIsEnabled) {
|
||||
// If locale switching is disabled, remove the section
|
||||
// entirely. This logic will need to be extended when
|
||||
// content language selection (Bug 881510) is implemented.
|
||||
iterator.remove();
|
||||
} else if (header.id == R.id.pref_header_devtools && !RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_DEVELOPER_TOOLS)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -703,6 +708,14 @@ OnSharedPreferenceChangeListener
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PREFS_CUSTOMIZE_HOME.equals(key)) {
|
||||
if (!RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_CUSTOMIZE_HOME)) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
setupPreferences((PreferenceGroup) pref, prefs);
|
||||
} else {
|
||||
pref.setOnPreferenceChangeListener(this);
|
||||
@ -727,7 +740,7 @@ OnSharedPreferenceChangeListener
|
||||
}
|
||||
} else if (PREFS_OPEN_URLS_IN_PRIVATE.equals(key)) {
|
||||
// Remove UI for opening external links in private browsing on non-Nightly builds.
|
||||
if (!AppConstants.NIGHTLY_BUILD) {
|
||||
if (!AppConstants.NIGHTLY_BUILD || !RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_PRIVATE_BROWSING)) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
@ -753,19 +766,19 @@ OnSharedPreferenceChangeListener
|
||||
}
|
||||
} else if (PREFS_GEO_REPORTING.equals(key) ||
|
||||
PREFS_GEO_LEARN_MORE.equals(key)) {
|
||||
if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED) {
|
||||
if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED || !RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_LOCATION_SERVICE)) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
} else if (PREFS_DEVTOOLS_REMOTE_USB_ENABLED.equals(key)) {
|
||||
if (!RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_REMOTE_DEBUGGING)) {
|
||||
if (!RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_REMOTE_DEBUGGING)) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
} else if (PREFS_DEVTOOLS_REMOTE_WIFI_ENABLED.equals(key)) {
|
||||
if (!RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_REMOTE_DEBUGGING)) {
|
||||
if (!RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_REMOTE_DEBUGGING)) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
@ -788,7 +801,7 @@ OnSharedPreferenceChangeListener
|
||||
continue;
|
||||
} else if (PREFS_SYNC.equals(key)) {
|
||||
// Don't show sync prefs while in guest mode.
|
||||
if (!RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
|
||||
if (!RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
@ -837,6 +850,18 @@ OnSharedPreferenceChangeListener
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
} else if (PREFS_TRACKING_PROTECTION_PRIVATE_BROWSING.equals(key)) {
|
||||
if (!RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_PRIVATE_BROWSING)) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
} else if (PREFS_TRACKING_PROTECTION_LEARN_MORE.equals(key)) {
|
||||
if (!RestrictedProfiles.isAllowed(this, Restriction.DISALLOW_PRIVATE_BROWSING)) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Some Preference UI elements are not actually preferences,
|
||||
|
@ -49,17 +49,19 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/new_tablet_tab_highlight_stroke_width"
|
||||
android:background="@drawable/tab_thumbnail"
|
||||
android:duplicateParentState="true">
|
||||
<org.mozilla.gecko.widget.TabThumbnailWrapper
|
||||
android:id="@+id/wrapper"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/new_tablet_tab_highlight_stroke_width"
|
||||
android:background="@drawable/tab_thumbnail"
|
||||
android:duplicateParentState="true">
|
||||
|
||||
<org.mozilla.gecko.widget.ThumbnailView android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/new_tablet_tab_thumbnail_width"
|
||||
android:layout_height="@dimen/new_tablet_tab_thumbnail_height"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
</org.mozilla.gecko.widget.TabThumbnailWrapper>
|
||||
|
||||
</org.mozilla.gecko.tabs.TabsLayoutItemView>
|
||||
|
@ -18,6 +18,6 @@
|
||||
android:background="@color/about_page_header_grey"
|
||||
android:layout_gravity="top"
|
||||
gecko:strip="@drawable/home_tab_menu_strip"
|
||||
gecko:tabContentStart="72dp" />
|
||||
gecko:tabContentStart="@dimen/tab_strip_content_start" />
|
||||
|
||||
</org.mozilla.gecko.home.HomePager>
|
||||
|
@ -16,8 +16,7 @@
|
||||
<org.mozilla.gecko.widget.GeckoSwipeRefreshLayout
|
||||
android:id="@id/remote_tabs_refresh_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:enabled="false">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -15,12 +15,14 @@
|
||||
android:paddingRight="1dip"
|
||||
android:gravity="center">
|
||||
|
||||
<RelativeLayout android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="6dip"
|
||||
android:padding="4dip"
|
||||
android:background="@drawable/tab_thumbnail"
|
||||
android:duplicateParentState="true">
|
||||
<org.mozilla.gecko.widget.TabThumbnailWrapper
|
||||
android:id="@+id/wrapper"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="6dip"
|
||||
android:padding="4dip"
|
||||
android:background="@drawable/tab_thumbnail"
|
||||
android:duplicateParentState="true">
|
||||
|
||||
<org.mozilla.gecko.widget.ThumbnailView android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/tab_thumbnail_width"
|
||||
@ -55,6 +57,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</org.mozilla.gecko.widget.TabThumbnailWrapper>
|
||||
|
||||
</org.mozilla.gecko.tabs.TabsLayoutItemView>
|
||||
|
@ -31,4 +31,6 @@
|
||||
<!-- Should be closer to 0.83 (140/168) but various roundings mean that 0.9 works better -->
|
||||
<item name="thumbnail_aspect_ratio" format="float" type="dimen">0.9</item>
|
||||
|
||||
<item name="tab_strip_content_start" type="dimen">72dp</item>
|
||||
|
||||
</resources>
|
||||
|
@ -215,4 +215,6 @@
|
||||
<item name="match_parent" type="dimen">-1</item>
|
||||
<item name="wrap_content" type="dimen">-2</item>
|
||||
|
||||
<item name="tab_strip_content_start" type="dimen">12dp</item>
|
||||
|
||||
</resources>
|
||||
|
@ -41,7 +41,8 @@
|
||||
</header>
|
||||
|
||||
<header android:fragment="org.mozilla.gecko.preferences.GeckoPreferenceFragment"
|
||||
android:title="@string/pref_header_devtools">
|
||||
android:title="@string/pref_header_devtools"
|
||||
android:id="@+id/pref_header_devtools">
|
||||
<extra android:name="resource"
|
||||
android:value="preferences_devtools"/>
|
||||
</header>
|
||||
|
@ -9,7 +9,8 @@
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto"
|
||||
android:enabled="false">
|
||||
|
||||
<PreferenceScreen android:title="@string/pref_category_home"
|
||||
<PreferenceScreen android:key="android.not_a_preference.customize_home"
|
||||
android:title="@string/pref_category_home"
|
||||
android:summary="@string/pref_category_home_summary"
|
||||
android:fragment="org.mozilla.gecko.preferences.GeckoPreferenceFragment" >
|
||||
<extra android:name="resource"
|
||||
|
@ -16,7 +16,8 @@
|
||||
android:title="@string/pref_sync"
|
||||
android:persistent="false" />
|
||||
|
||||
<PreferenceScreen android:title="@string/pref_category_home"
|
||||
<PreferenceScreen android:key="android.not_a_preference.customize_home"
|
||||
android:title="@string/pref_category_home"
|
||||
android:summary="@string/pref_category_home_summary"
|
||||
android:fragment="org.mozilla.gecko.preferences.GeckoPreferenceFragment" >
|
||||
<extra android:name="resource"
|
||||
|
@ -10,4 +10,7 @@
|
||||
<header android:fragment="org.mozilla.gecko.preferences.GeckoPreferenceFragment"
|
||||
android:id="@+id/pref_header_language">
|
||||
</header>
|
||||
<header android:fragment="org.mozilla.gecko.preferences.GeckoPreferenceFragment"
|
||||
android:id="@+id/pref_header_devtools">
|
||||
</header>
|
||||
</preference-headers>
|
||||
|
@ -7,7 +7,9 @@
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto"
|
||||
android:enabled="false">
|
||||
|
||||
<PreferenceScreen android:title="@string/pref_category_home"
|
||||
<PreferenceScreen
|
||||
android:key="android.not_a_preference.customize_home"
|
||||
android:title="@string/pref_category_home"
|
||||
android:summary="@string/pref_category_home_summary" >
|
||||
<intent android:action="android.intent.action.VIEW"
|
||||
android:targetPackage="@string/android_package_name"
|
||||
|
27
mobile/android/base/restrictions/DefaultConfiguration.java
Normal file
27
mobile/android/base/restrictions/DefaultConfiguration.java
Normal file
@ -0,0 +1,27 @@
|
||||
/* -*- 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.restrictions;
|
||||
|
||||
/**
|
||||
* Default implementation of RestrictionConfiguration interface. Used whenever no restrictions are enforced for the
|
||||
* current profile.
|
||||
*/
|
||||
public class DefaultConfiguration implements RestrictionConfiguration {
|
||||
@Override
|
||||
public boolean isAllowed(Restriction restriction) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLoadUrl(String url) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRestricted() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/* -*- 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.restrictions;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* RestrictionConfiguration implementation for guest profiles.
|
||||
*/
|
||||
public class GuestProfileConfiguration implements RestrictionConfiguration {
|
||||
static List<Restriction> DEFAULT_RESTRICTIONS = Arrays.asList(
|
||||
Restriction.DISALLOW_DOWNLOADS,
|
||||
Restriction.DISALLOW_INSTALL_EXTENSION,
|
||||
Restriction.DISALLOW_INSTALL_APPS,
|
||||
Restriction.DISALLOW_BROWSE_FILES,
|
||||
Restriction.DISALLOW_SHARE,
|
||||
Restriction.DISALLOW_BOOKMARK,
|
||||
Restriction.DISALLOW_ADD_CONTACTS,
|
||||
Restriction.DISALLOW_SET_IMAGE,
|
||||
Restriction.DISALLOW_MODIFY_ACCOUNTS,
|
||||
Restriction.DISALLOW_REMOTE_DEBUGGING,
|
||||
Restriction.DISALLOW_IMPORT_SETTINGS
|
||||
);
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static final List<String> BANNED_SCHEMES = Arrays.asList(
|
||||
"file",
|
||||
"chrome",
|
||||
"resource",
|
||||
"jar",
|
||||
"wyciwyg"
|
||||
);
|
||||
|
||||
private static final List<String> BANNED_URLS = Arrays.asList(
|
||||
"about:config"
|
||||
);
|
||||
|
||||
@Override
|
||||
public boolean isAllowed(Restriction restriction) {
|
||||
return !DEFAULT_RESTRICTIONS.contains(restriction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLoadUrl(String url) {
|
||||
// Null URLs are always permitted.
|
||||
if (url == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Uri u = Uri.parse(url);
|
||||
final String scheme = u.getScheme();
|
||||
if (BANNED_SCHEMES.contains(scheme)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String banned : BANNED_URLS) {
|
||||
if (url.startsWith(banned)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRestricted() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/* -*- 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.restrictions;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class RestrictedProfileConfiguration implements RestrictionConfiguration {
|
||||
static List<Restriction> DEFAULT_RESTRICTIONS = Arrays.asList(
|
||||
Restriction.DISALLOW_INSTALL_EXTENSION,
|
||||
Restriction.DISALLOW_INSTALL_APPS,
|
||||
Restriction.DISALLOW_TOOLS_MENU,
|
||||
Restriction.DISALLOW_REPORT_SITE_ISSUE,
|
||||
Restriction.DISALLOW_IMPORT_SETTINGS,
|
||||
Restriction.DISALLOW_DEVELOPER_TOOLS,
|
||||
Restriction.DISALLOW_CUSTOMIZE_HOME,
|
||||
Restriction.DISALLOW_PRIVATE_BROWSING,
|
||||
Restriction.DISALLOW_LOCATION_SERVICE
|
||||
);
|
||||
|
||||
private static final String ABOUT_ADDONS = "about:addons";
|
||||
private static final String ABOUT_PRIVATE_BROWSING = "about:privatebrowsing";
|
||||
|
||||
private Context context;
|
||||
|
||||
public RestrictedProfileConfiguration(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed(Restriction restriction) {
|
||||
boolean isAllowed = !getAppRestrictions(context).getBoolean(restriction.name, DEFAULT_RESTRICTIONS.contains(restriction));
|
||||
|
||||
if (isAllowed) {
|
||||
// If this restriction is not enforced by the app setup then check wether this is a restriction that is
|
||||
// enforced by the system.
|
||||
isAllowed = !getUserRestrictions(context).getBoolean(restriction.name, false);
|
||||
}
|
||||
|
||||
return isAllowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLoadUrl(String url) {
|
||||
if (!isAllowed(Restriction.DISALLOW_INSTALL_EXTENSION) && url.toLowerCase().startsWith(ABOUT_ADDONS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isAllowed(Restriction.DISALLOW_PRIVATE_BROWSING) && url.toLowerCase().startsWith(ABOUT_PRIVATE_BROWSING)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRestricted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
private Bundle getAppRestrictions(final Context context) {
|
||||
final UserManager mgr = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
return mgr.getApplicationRestrictions(context.getPackageName());
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
private Bundle getUserRestrictions(final Context context) {
|
||||
final UserManager mgr = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
return mgr.getUserRestrictions();
|
||||
}
|
||||
}
|
118
mobile/android/base/restrictions/Restriction.java
Normal file
118
mobile/android/base/restrictions/Restriction.java
Normal file
@ -0,0 +1,118 @@
|
||||
/* -*- 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.restrictions;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* This is a list of things we can restrict you from doing. Some of these are reflected in Android UserManager constants.
|
||||
* Others are specific to us.
|
||||
* These constants should be in sync with the ones from toolkit/components/parentalcontrols/nsIParentalControlsService.idl
|
||||
*/
|
||||
public enum Restriction {
|
||||
DISALLOW_DOWNLOADS(
|
||||
1, "no_download_files", 0, 0),
|
||||
|
||||
DISALLOW_INSTALL_EXTENSION(
|
||||
2, "no_install_extensions",
|
||||
R.string.restriction_disallow_addons_title,
|
||||
R.string.restriction_disallow_addons_description),
|
||||
|
||||
// UserManager.DISALLOW_INSTALL_APPS
|
||||
DISALLOW_INSTALL_APPS(
|
||||
3, "no_install_apps",
|
||||
R.string.restriction_disallow_apps_title,
|
||||
R.string.restriction_disallow_apps_description),
|
||||
|
||||
DISALLOW_BROWSE_FILES(
|
||||
4, "no_browse_files", 0, 0),
|
||||
|
||||
DISALLOW_SHARE(
|
||||
5, "no_share", 0, 0),
|
||||
|
||||
DISALLOW_BOOKMARK(
|
||||
6, "no_bookmark", 0, 0),
|
||||
|
||||
DISALLOW_ADD_CONTACTS(
|
||||
7, "no_add_contacts", 0, 0),
|
||||
|
||||
DISALLOW_SET_IMAGE(
|
||||
8, "no_set_image", 0, 0),
|
||||
|
||||
// UserManager.DISALLOW_MODIFY_ACCOUNTS
|
||||
DISALLOW_MODIFY_ACCOUNTS(
|
||||
9, "no_modify_accounts", 0, 0),
|
||||
|
||||
DISALLOW_REMOTE_DEBUGGING(
|
||||
10, "no_remote_debugging", 0, 0),
|
||||
|
||||
DISALLOW_IMPORT_SETTINGS(
|
||||
11, "no_report_site_issue",
|
||||
R.string.restriction_disallow_import_settings_title,
|
||||
R.string.restriction_disallow_import_settings_description),
|
||||
|
||||
DISALLOW_TOOLS_MENU(
|
||||
12, "no_tools_menu",
|
||||
R.string.restriction_disallow_tools_menu_title,
|
||||
R.string.restriction_disallow_tools_menu_description),
|
||||
|
||||
DISALLOW_REPORT_SITE_ISSUE(
|
||||
13, "no_report_site_issue",
|
||||
R.string.restriction_disallow_report_site_issue_title,
|
||||
R.string.restriction_disallow_report_site_issue_description),
|
||||
|
||||
DISALLOW_DEVELOPER_TOOLS(
|
||||
14, "no_developer_tools",
|
||||
R.string.restriction_disallow_devtools_title,
|
||||
R.string.restriction_disallow_devtools_description
|
||||
),
|
||||
|
||||
DISALLOW_CUSTOMIZE_HOME(
|
||||
15, "no_customize_home",
|
||||
R.string.restriction_disallow_customize_home_title,
|
||||
R.string.restriction_disallow_customize_home_description
|
||||
),
|
||||
|
||||
DISALLOW_PRIVATE_BROWSING(
|
||||
16, "no_private_browsing",
|
||||
R.string.restriction_disallow_private_browsing_title,
|
||||
R.string.restriction_disallow_private_browsing_description
|
||||
),
|
||||
|
||||
DISALLOW_LOCATION_SERVICE(
|
||||
17, "no_location_service",
|
||||
R.string.restriction_disallow_location_services_title,
|
||||
R.string.restriction_disallow_location_services_description
|
||||
);
|
||||
|
||||
public final int id;
|
||||
public final String name;
|
||||
public final int titleResource;
|
||||
public final int descriptionResource;
|
||||
|
||||
Restriction(final int id, final String name, int titleResource, int descriptionResource) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.titleResource = titleResource;
|
||||
this.descriptionResource = descriptionResource;
|
||||
}
|
||||
|
||||
public String getTitle(Context context) {
|
||||
if (titleResource == 0) {
|
||||
return toString();
|
||||
}
|
||||
return context.getResources().getString(titleResource);
|
||||
}
|
||||
|
||||
public String getDescription(Context context) {
|
||||
if (descriptionResource == 0) {
|
||||
return name;
|
||||
}
|
||||
return context.getResources().getString(descriptionResource);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/* -*- 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.restrictions;
|
||||
|
||||
/**
|
||||
* Interface for classes that RestrictedProfiles will delegate to for making decisions.
|
||||
*/
|
||||
public interface RestrictionConfiguration {
|
||||
/**
|
||||
* Is the user allowed to perform this action?
|
||||
*/
|
||||
boolean isAllowed(Restriction restriction);
|
||||
|
||||
/**
|
||||
* Is the user allowed to load the given URL?
|
||||
*/
|
||||
boolean canLoadUrl(String url);
|
||||
|
||||
/**
|
||||
* Is this user restricted in any way?
|
||||
*/
|
||||
boolean isRestricted();
|
||||
}
|
@ -3,7 +3,11 @@
|
||||
* 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;
|
||||
package org.mozilla.gecko.restrictions;
|
||||
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.restrictions.RestrictedProfileConfiguration;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
@ -13,7 +17,6 @@ import android.content.Intent;
|
||||
import android.content.RestrictionEntry;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -49,7 +52,7 @@ public class RestrictionProvider extends BroadcastReceiver {
|
||||
private ArrayList<RestrictionEntry> initRestrictions(Context context, Bundle oldRestrictions) {
|
||||
ArrayList<RestrictionEntry> entries = new ArrayList<RestrictionEntry>();
|
||||
|
||||
for (RestrictedProfiles.Restriction restriction : RestrictedProfiles.RESTRICTED_PROFILE_RESTRICTIONS) {
|
||||
for (Restriction restriction : RestrictedProfileConfiguration.DEFAULT_RESTRICTIONS) {
|
||||
RestrictionEntry entry = createRestrictionEntryWithDefaultValue(context, restriction,
|
||||
oldRestrictions.getBoolean(restriction.name, true));
|
||||
entries.add(entry);
|
||||
@ -58,7 +61,7 @@ public class RestrictionProvider extends BroadcastReceiver {
|
||||
return entries;
|
||||
}
|
||||
|
||||
private RestrictionEntry createRestrictionEntryWithDefaultValue(Context context, RestrictedProfiles.Restriction restriction, boolean defaultValue) {
|
||||
private RestrictionEntry createRestrictionEntryWithDefaultValue(Context context, Restriction restriction, boolean defaultValue) {
|
||||
RestrictionEntry entry = new RestrictionEntry(restriction.name, defaultValue);
|
||||
|
||||
entry.setTitle(restriction.getTitle(context));
|
@ -549,6 +549,14 @@
|
||||
<string name="restriction_disallow_addons_description">&restriction_disallow_addons_description;</string>
|
||||
<string name="restriction_disallow_apps_title">&restriction_disallow_apps_title;</string>
|
||||
<string name="restriction_disallow_apps_description">&restriction_disallow_apps_description;</string>
|
||||
<string name="restriction_disallow_devtools_title">&restriction_disallow_devtools_title;</string>
|
||||
<string name="restriction_disallow_devtools_description">&restriction_disallow_devtools_description;</string>
|
||||
<string name="restriction_disallow_customize_home_title">&restriction_disallow_customize_home_title;</string>
|
||||
<string name="restriction_disallow_customize_home_description">&restriction_disallow_customize_home_description;</string>
|
||||
<string name="restriction_disallow_private_browsing_title">&restriction_disallow_private_browsing_title;</string>
|
||||
<string name="restriction_disallow_private_browsing_description">&restriction_disallow_private_browsing_description;</string>
|
||||
<string name="restriction_disallow_location_services_title">&restriction_disallow_location_services_title;</string>
|
||||
<string name="restriction_disallow_location_services_description">&restriction_disallow_location_services_description;</string>
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<string name="ellipsis">&ellipsis;</string>
|
||||
|
@ -9,14 +9,16 @@ import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.RestrictedProfiles;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.animation.ViewHelper;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.lwt.LightweightThemeDrawable;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.widget.GeckoPopupMenu;
|
||||
import org.mozilla.gecko.widget.IconTabWidget;
|
||||
@ -139,6 +141,10 @@ public class TabsPanel extends LinearLayout
|
||||
mTabWidget.addTab(R.drawable.tabs_normal, R.string.tabs_normal);
|
||||
mTabWidget.addTab(R.drawable.tabs_private, R.string.tabs_private);
|
||||
|
||||
if (!RestrictedProfiles.isAllowed(mContext, Restriction.DISALLOW_PRIVATE_BROWSING)) {
|
||||
mTabWidget.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
mTabWidget.setTabSelectionListener(this);
|
||||
|
||||
mMenuButton = (ImageButton) findViewById(R.id.menu);
|
||||
@ -166,7 +172,8 @@ public class TabsPanel extends LinearLayout
|
||||
|
||||
// Each panel has a "+" shortcut button, so don't show it for that panel.
|
||||
menu.findItem(R.id.new_tab).setVisible(mCurrentPanel != Panel.NORMAL_TABS);
|
||||
menu.findItem(R.id.new_private_tab).setVisible(mCurrentPanel != Panel.PRIVATE_TABS);
|
||||
menu.findItem(R.id.new_private_tab).setVisible(mCurrentPanel != Panel.PRIVATE_TABS
|
||||
&& RestrictedProfiles.isAllowed(mContext, Restriction.DISALLOW_PRIVATE_BROWSING));
|
||||
|
||||
// Only show "Clear * tabs" for current panel.
|
||||
menu.findItem(R.id.close_all_tabs).setVisible(mCurrentPanel == Panel.NORMAL_TABS);
|
||||
|
@ -2,11 +2,11 @@ package org.mozilla.gecko.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
|
||||
public class TabThumbnailWrapper extends FrameLayout {
|
||||
public class TabThumbnailWrapper extends RelativeLayout {
|
||||
private boolean mRecording;
|
||||
private static final int[] STATE_RECORDING = { R.attr.state_recording };
|
||||
|
||||
|
@ -7,8 +7,8 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -7,8 +7,8 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -7,8 +7,8 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -7,8 +7,8 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -7,8 +7,8 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -7,8 +7,8 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -7,8 +7,8 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -7,8 +7,8 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -8,7 +8,7 @@
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.LightweightTheme;
|
||||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -38,6 +38,11 @@ function copyStringAndToast(string, notifyString) {
|
||||
|
||||
// Delay filtering while typing in MS
|
||||
const FILTER_DELAY = 500;
|
||||
/* Constants for usage telemetry */
|
||||
const LOGINS_LIST_VIEWED = 0;
|
||||
const LOGIN_VIEWED = 1;
|
||||
const LOGIN_EDITED = 2;
|
||||
const LOGIN_PW_TOGGLED = 3;
|
||||
|
||||
let Logins = {
|
||||
_logins: [],
|
||||
@ -162,6 +167,7 @@ let Logins = {
|
||||
},
|
||||
|
||||
_showList: function () {
|
||||
Services.telemetry.getHistogramById("PWMGR_ABOUT_LOGINS_USAGE").add(LOGINS_LIST_VIEWED);
|
||||
let loginsListPage = document.getElementById("logins-list-page");
|
||||
loginsListPage.classList.remove("hidden");
|
||||
|
||||
@ -184,6 +190,7 @@ let Logins = {
|
||||
}
|
||||
},
|
||||
_showEditLoginDialog: function (login) {
|
||||
Services.telemetry.getHistogramById("PWMGR_ABOUT_LOGINS_USAGE").add(LOGIN_VIEWED);
|
||||
let listPage = document.getElementById("logins-list-page");
|
||||
listPage.classList.add("hidden");
|
||||
|
||||
@ -210,6 +217,7 @@ let Logins = {
|
||||
},
|
||||
|
||||
_onSaveEditLogin: function() {
|
||||
Services.telemetry.getHistogramById("PWMGR_ABOUT_LOGINS_USAGE").add(LOGIN_EDITED);
|
||||
let newUsername = document.getElementById("username").value;
|
||||
let newPassword = document.getElementById("password").value;
|
||||
let newDomain = document.getElementById("hostname").value;
|
||||
@ -248,6 +256,7 @@ let Logins = {
|
||||
},
|
||||
|
||||
_onPasswordBtn: function () {
|
||||
Services.telemetry.getHistogramById("PWMGR_ABOUT_LOGINS_USAGE").add(LOGIN_PW_TOGGLED);
|
||||
this._updatePasswordBtn(this._isPasswordBtnInHideMode());
|
||||
},
|
||||
|
||||
|
@ -690,27 +690,35 @@ var BrowserApp = {
|
||||
});
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(stringGetter("contextmenu.openInPrivateTab"),
|
||||
NativeWindow.contextmenus.linkOpenableContext,
|
||||
function(aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_open_private_tab");
|
||||
UITelemetry.addEvent("loadurl.1", "contextmenu", null);
|
||||
let showOpenInPrivateTab = true;
|
||||
if ("@mozilla.org/parental-controls-service;1" in Cc) {
|
||||
let pc = Cc["@mozilla.org/parental-controls-service;1"].createInstance(Ci.nsIParentalControlsService);
|
||||
showOpenInPrivateTab = pc.isAllowed(Ci.nsIParentalControlsService.PRIVATE_BROWSING);
|
||||
}
|
||||
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
ContentAreaUtils.urlSecurityCheck(url, aTarget.ownerDocument.nodePrincipal);
|
||||
let tab = BrowserApp.addTab(url, { selected: false, parentId: BrowserApp.selectedTab.id, isPrivate: true });
|
||||
if (showOpenInPrivateTab) {
|
||||
NativeWindow.contextmenus.add(stringGetter("contextmenu.openInPrivateTab"),
|
||||
NativeWindow.contextmenus.linkOpenableContext,
|
||||
function (aTarget) {
|
||||
UITelemetry.addEvent("action.1", "contextmenu", null, "web_open_private_tab");
|
||||
UITelemetry.addEvent("loadurl.1", "contextmenu", null);
|
||||
|
||||
let newtabStrings = Strings.browser.GetStringFromName("newprivatetabpopup.opened");
|
||||
let label = PluralForm.get(1, newtabStrings).replace("#1", 1);
|
||||
let buttonLabel = Strings.browser.GetStringFromName("newtabpopup.switch");
|
||||
NativeWindow.toast.show(label, "long", {
|
||||
button: {
|
||||
icon: "drawable://switch_button_icon",
|
||||
label: buttonLabel,
|
||||
callback: () => { BrowserApp.selectTab(tab); },
|
||||
}
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
ContentAreaUtils.urlSecurityCheck(url, aTarget.ownerDocument.nodePrincipal);
|
||||
let tab = BrowserApp.addTab(url, {selected: false, parentId: BrowserApp.selectedTab.id, isPrivate: true});
|
||||
|
||||
let newtabStrings = Strings.browser.GetStringFromName("newprivatetabpopup.opened");
|
||||
let label = PluralForm.get(1, newtabStrings).replace("#1", 1);
|
||||
let buttonLabel = Strings.browser.GetStringFromName("newtabpopup.switch");
|
||||
NativeWindow.toast.show(label, "long", {
|
||||
button: {
|
||||
icon: "drawable://switch_button_icon",
|
||||
label: buttonLabel,
|
||||
callback: () => { BrowserApp.selectTab(tab); },
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
NativeWindow.contextmenus.add(stringGetter("contextmenu.addToReadingList"),
|
||||
NativeWindow.contextmenus.linkOpenableContext,
|
||||
|
@ -29,27 +29,4 @@ add_task(function test_isUserRestricted() {
|
||||
do_check_true(pc.isAllowed(Ci.nsIParentalControlsService.MODIFY_ACCOUNTS));
|
||||
});
|
||||
|
||||
add_task(function test_getUserRestrictions() {
|
||||
// In an admin profile, like the tests: {}
|
||||
// In a restricted profile: {"no_modify_accounts":true,"no_share_location":true}
|
||||
let restrictions = "{}";
|
||||
|
||||
var jenv = null;
|
||||
try {
|
||||
jenv = JNI.GetForThread();
|
||||
var profile = JNI.LoadClass(jenv, "org.mozilla.gecko.RestrictedProfiles", {
|
||||
static_methods: [
|
||||
{ name: "getUserRestrictions", sig: "()Ljava/lang/String;" },
|
||||
],
|
||||
});
|
||||
restrictions = JNI.ReadString(jenv, profile.getUserRestrictions());
|
||||
} finally {
|
||||
if (jenv) {
|
||||
JNI.UnloadClasses(jenv);
|
||||
}
|
||||
}
|
||||
|
||||
do_check_eq(restrictions, "{}");
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
|
@ -213,6 +213,7 @@ body {
|
||||
.empty-text {
|
||||
color: #363B40;
|
||||
font-size: 25px;
|
||||
font-weight: lighter;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ interface nsIFile;
|
||||
interface nsIInterfaceRequestor;
|
||||
interface nsIArray;
|
||||
|
||||
[scriptable, uuid(406808a5-2838-4c29-9e39-5bfb885c89bf)]
|
||||
[scriptable, uuid(4ee714a7-e9a8-43ed-a061-60155b63e290)]
|
||||
interface nsIParentalControlsService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -30,6 +30,8 @@ interface nsIParentalControlsService : nsISupports
|
||||
const short IMPORT_SETTINGS = 11; // Importing settings from other apps
|
||||
const short TOOLS_MENU = 12; // Hide tools menu entry
|
||||
const short REPORT_SITE_ISSUE = 13; // Hide "Report Site Issue" menu entry
|
||||
const short PRIVATE_BROWSING = 16; // Disallow usage of private browsing
|
||||
const short LOCATION_SERVICE = 17; // Sharing of location data to location service
|
||||
|
||||
/**
|
||||
* @returns true if the current user account has parental controls
|
||||
|
@ -3387,7 +3387,7 @@
|
||||
"description": "Number of thumbnails stored in the browser DB *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***"
|
||||
},
|
||||
"FENNEC_READING_LIST_COUNT": {
|
||||
"expires_in_version": "40",
|
||||
"expires_in_version": "50",
|
||||
"kind": "exponential",
|
||||
"high": "1000",
|
||||
"n_buckets": 10,
|
||||
@ -8231,6 +8231,12 @@
|
||||
"extended_statistics_ok": true,
|
||||
"description": "How long getAllLogins() on about:logins takes for mobile users"
|
||||
},
|
||||
"PWMGR_ABOUT_LOGINS_USAGE": {
|
||||
"expires_in_version": "55",
|
||||
"kind": "enumerated",
|
||||
"n_values": 12,
|
||||
"description": "Usage of about:logins 0= list of logins viewed, 1=a login's specifics page was viewed, 2=user edited login credentials 3=user toggled the show/hide button"
|
||||
},
|
||||
"PWMGR_BLOCKLIST_NUM_SITES": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
|
@ -765,14 +765,6 @@ void GeckoJavaSampler::UnpauseJavaProfiling()
|
||||
|
||||
constexpr char RestrictedProfiles::name[];
|
||||
|
||||
constexpr char RestrictedProfiles::GetUserRestrictions_t::name[];
|
||||
constexpr char RestrictedProfiles::GetUserRestrictions_t::signature[];
|
||||
|
||||
mozilla::jni::String::LocalRef RestrictedProfiles::GetUserRestrictions()
|
||||
{
|
||||
return mozilla::jni::Method<GetUserRestrictions_t>::Call(nullptr, nullptr);
|
||||
}
|
||||
|
||||
constexpr char RestrictedProfiles::IsAllowed_t::name[];
|
||||
constexpr char RestrictedProfiles::IsAllowed_t::signature[];
|
||||
|
||||
|
@ -1818,23 +1818,6 @@ public:
|
||||
protected:
|
||||
RestrictedProfiles(jobject instance) : Class(instance) {}
|
||||
|
||||
public:
|
||||
struct GetUserRestrictions_t {
|
||||
typedef RestrictedProfiles Owner;
|
||||
typedef mozilla::jni::String::LocalRef ReturnType;
|
||||
typedef mozilla::jni::String::Param SetterType;
|
||||
typedef mozilla::jni::Args<> Args;
|
||||
static constexpr char name[] = "getUserRestrictions";
|
||||
static constexpr char signature[] =
|
||||
"()Ljava/lang/String;";
|
||||
static const bool isStatic = true;
|
||||
static const bool isMultithreaded = false;
|
||||
static const mozilla::jni::ExceptionMode exceptionMode =
|
||||
mozilla::jni::ExceptionMode::ABORT;
|
||||
};
|
||||
|
||||
static mozilla::jni::String::LocalRef GetUserRestrictions();
|
||||
|
||||
public:
|
||||
struct IsAllowed_t {
|
||||
typedef RestrictedProfiles Owner;
|
||||
|
Loading…
Reference in New Issue
Block a user