Merge fx-team to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-07-30 15:54:37 -04:00
commit c7aa4e5782
88 changed files with 3206 additions and 4189 deletions

View File

@ -489,6 +489,7 @@
@BINPATH@/components/nsInputListAutoComplete.js
@BINPATH@/components/formautofill.manifest
@BINPATH@/components/FormAutofillContentService.js
@BINPATH@/components/FormAutofillStartup.js
@BINPATH@/components/contentSecurityPolicy.manifest
@BINPATH@/components/contentSecurityPolicy.js
@BINPATH@/components/contentAreaDropListener.manifest

View File

@ -917,22 +917,6 @@
cui-areatype="toolbar"
aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
<!-- XXX Bug 1013989 will provide a label for the button -->
<!-- This uses badged to be compatible with the social api code it shares.
We may also want it to be badged in the future, for notification
purposes. -->
<toolbarbutton id="loop-call-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
persist="class"
type="badged"
removable="true"
tooltiptext="&loopCallButton.tooltip;"
oncommand="LoopUI.openCallPanel(event);"
cui-areatype="toolbar"
>
</toolbarbutton>
<toolbarbutton id="social-share-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&sharePageCmd.label;"

View File

@ -52,7 +52,7 @@ const kSubviewEvents = [
* The current version. We can use this to auto-add new default widgets as necessary.
* (would be const but isn't because of testing purposes)
*/
let kVersion = 0;
let kVersion = 1;
/**
* gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed

View File

@ -898,6 +898,28 @@ const CustomizableWidgets = [{
let win = aEvent.view;
win.MailIntegration.sendLinkForWindow(win.content);
}
}, {
id: "loop-call-button",
type: "custom",
// XXX Bug 1013989 will provide a label for the button
label: "loop-call-button.label",
tooltiptext: "loop-call-button.tooltiptext",
defaultArea: CustomizableUI.AREA_NAVBAR,
introducedInVersion: 1,
onBuild: function(aDocument) {
let node = aDocument.createElementNS(kNSXUL, "toolbarbutton");
node.setAttribute("id", this.id);
node.classList.add("toolbarbutton-1");
node.classList.add("chromeclass-toolbar-additional");
node.setAttribute("type", "badged");
node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
node.setAttribute("removable", "true");
node.addEventListener("command", function(event) {
aDocument.defaultView.LoopUI.openCallPanel(event);
});
return node;
}
}];
#ifdef XP_WIN

View File

@ -83,19 +83,19 @@ function updateUI() {
document.querySelector("#type").classList.remove("hidden");
if (project.type == "runtimeApp") {
let manifest = AppManager.getProjectManifestURL(project);
let manifestURL = AppManager.getProjectManifestURL(project);
document.querySelector("#type").textContent = manifest.type || "web";
document.querySelector("#manifestURLHeader").classList.remove("hidden");
document.querySelector("#manifestURL").textContent = manifest;
document.querySelector("#manifestURL").textContent = manifestURL;
} else {
document.querySelector("#type").textContent = project.type + " " + (manifest.type || "web");
}
if (project.type == "packaged") {
let manifest = AppManager.getProjectManifestURL(project);
if (manifest) {
let manifestURL = AppManager.getProjectManifestURL(project);
if (manifestURL) {
document.querySelector("#manifestURLHeader").classList.remove("hidden");
document.querySelector("#manifestURL").textContent = manifest;
document.querySelector("#manifestURL").textContent = manifestURL;
}
}
}

View File

@ -58,6 +58,16 @@
<h2>&prefs_editor_title;</h2>
<ul>
<li>
<label><span>&prefs_options_keybindings;</span>
<select data-pref="devtools.editor.keymap">
<option value="default">&prefs_options_keybindings_default;</option>
<option value="vim">Vim</option>
<option value="emacs">Emacs</option>
<option value="sublime">Sublime</option>
</select>
</label>
</li>
<li>
<label><span>&prefs_options_tabsize;</span>
<select data-pref="devtools.editor.tabsize">

View File

@ -632,7 +632,7 @@ let UI = {
splitter.removeAttribute("hidden");
let iframe = document.createElement("iframe");
document.querySelector("window").insertBefore(iframe, splitter.nextSibling);
document.querySelector("notificationbox").insertBefore(iframe, splitter.nextSibling);
let host = devtools.Toolbox.HostType.CUSTOM;
let options = { customIframe: iframe };
this.toolboxIframe = iframe;

View File

@ -181,10 +181,9 @@
<iframe id="deck-panel-runtimedetails" flex="1" src="runtimedetails.xhtml"/>
<iframe id="deck-panel-monitor" flex="1" lazysrc="monitor.xhtml"/>
</deck>
<splitter hidden="true" class="devtools-horizontal-splitter" orient="vertical"/>
<!-- toolbox iframe will be inserted here -->
</notificationbox>
<splitter hidden="true" class="devtools-horizontal-splitter" orient="vertical"/>
<!-- toolbox iframe will be inserted here -->
</window>

View File

@ -117,6 +117,8 @@
<!ENTITY prefs_options_autocomplete_tooltip "Enable code autocompletion">
<!ENTITY prefs_options_autoclosebrackets "Autoclose brackets">
<!ENTITY prefs_options_autoclosebrackets_tooltip "Automatically insert closing brackets">
<!ENTITY prefs_options_keybindings "Keybindings">
<!ENTITY prefs_options_keybindings_default "Default">
<!-- Permissions Table -->
<!ENTITY permissionstable_title "Permissions Table">

View File

@ -451,6 +451,7 @@
@BINPATH@/components/nsInputListAutoComplete.js
@BINPATH@/components/formautofill.manifest
@BINPATH@/components/FormAutofillContentService.js
@BINPATH@/components/FormAutofillStartup.js
@BINPATH@/components/contentSecurityPolicy.manifest
@BINPATH@/components/contentSecurityPolicy.js
@BINPATH@/components/contentAreaDropListener.manifest

View File

@ -715,8 +715,6 @@ just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY getUserMedia.selectMicrophone.accesskey "M">
<!ENTITY getUserMedia.allWindowsShared.message "All visible windows on your screen will be shared.">
<!ENTITY loopCallButton.tooltip "Invite someone to talk">
<!ENTITY mixedContentBlocked.moreinfo "Most websites will still work properly even when this content is blocked.">
<!ENTITY pointerLock.notification.message "Press ESC at any time to show it again.">

View File

@ -96,3 +96,6 @@ quit-button.tooltiptext.linux2 = Quit %1$S (%2$S)
# LOCALIZATION NOTE(quit-button.tooltiptext.mac): %1$S is the brand name (e.g. Firefox),
# %2$S is the keyboard shortcut
quit-button.tooltiptext.mac = Quit %1$S (%2$S)
loop-call-button.label = Invite someone to talk
loop-call-button.tooltiptext = Invite someone to talk

View File

@ -14,6 +14,8 @@ skip-if = buildapp == 'mulet'
[test_bug477754.xul]
[test_bug703150.xul]
skip-if = buildapp == 'mulet'
[test_bug987230.xul]
skip-if = os == 'linux' # No native mousedown event
[test_popupSizeTo.xul]
[test_resizer.xul]
[test_stack.xul]

View File

@ -0,0 +1,115 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=987230
-->
<window title="Mozilla Bug 987230"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="SimpleTest.waitForFocus(nextTest, window)">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=987230"
target="_blank">Mozilla Bug 987230</a>
</body>
<vbox>
<toolbar>
<toolbarbutton id="toolbarbutton-anchor"
label="Anchor"
consumeanchor="toolbarbutton-anchor"
onclick="onAnchorClick(event)"
style="padding: 50px !important; list-style-image: url(chrome://branding/content/icon32.png)"/>
</toolbar>
<spacer flex="1"/>
<hbox id="hbox-anchor"
style="padding: 20px"
onclick="onAnchorClick(event)">
<hbox id="inner-anchor"
consumeanchor="hbox-anchor"
>
Another anchor
</hbox>
</hbox>
<spacer flex="1"/>
</vbox>
<panel id="mypopup"
type="arrow"
onpopupshown="onMyPopupShown(event)"
onpopuphidden="onMyPopupHidden(event)">This is a test popup</panel>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 987230 **/
SimpleTest.waitForExplicitFinish();
const Ci = Components.interfaces;
const Cc = Components.classes;
let platform = navigator.platform.toLowerCase();
let isWindows = platform.startsWith("win");
let mouseDown = isWindows ? 2 : 1;
let mouseUp = isWindows ? 4 : 2;
let mouseMove = isWindows ? 1 : 5;
let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let scale = utils.screenPixelsPerCSSPixel;
function synthesizeNativeMouseClick(aElement, aOffsetX, aOffsetY) {
let rect = aElement.getBoundingClientRect();
let win = aElement.ownerDocument.defaultView;
let x = aOffsetX + win.mozInnerScreenX + rect.left;
let y = aOffsetY + win.mozInnerScreenY + rect.top;
utils.sendNativeMouseEvent(x * scale, y * scale, mouseDown, 0, null);
utils.sendNativeMouseEvent(x * scale, y * scale, mouseUp, 0, null);
}
function onMyPopupHidden(e) {
ok(true, "Popup hidden");
if (outerAnchor.id == "toolbarbutton-anchor") {
popupHasShown = false;
outerAnchor = document.getElementById("hbox-anchor");
anchor = document.getElementById("inner-anchor");
nextTest();
} else {
//XXXgijs set mouse position back outside the iframe:
let frameRect = window.frameElement.getBoundingClientRect();
let outsideOfFrameX = (window.mozInnerScreenX + frameRect.width + 100) * scale;
let outsideOfFrameY = Math.max(0, window.mozInnerScreenY - 100) * scale;
utils.sendNativeMouseEvent(outsideOfFrameX, outsideOfFrameY, mouseMove, 0, null);
SimpleTest.finish();
}
}
let popupHasShown = false;
function onMyPopupShown(e) {
popupHasShown = true;
synthesizeNativeMouseClick(outerAnchor, 5, 5);
}
function onAnchorClick(e) {
info("click: " + e.target.id);
ok(!popupHasShown, "Popup should only be shown once");
popup.openPopup(anchor, "bottomcenter topright");
}
let popup = document.getElementById("mypopup");
let outerAnchor = document.getElementById("toolbarbutton-anchor");
let anchor = document.getAnonymousElementByAttribute(outerAnchor, "class", "toolbarbutton-icon");
function nextTest(e) {
synthesizeMouse(outerAnchor, 5, 5, {});
}
]]>
</script>
</window>

View File

@ -5,28 +5,22 @@
package org.mozilla.gecko;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.ThreadUtils;
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Build;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import java.lang.Math;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class AndroidGamepadManager {
// This is completely arbitrary.
@ -334,7 +328,7 @@ public class AndroidGamepadManager {
}
private static void addDeviceListener() {
if (Build.VERSION.SDK_INT < 16) {
if (Versions.preJB) {
// Poll known gamepads to see if they've disappeared.
sPollTimer = new Timer();
sPollTimer.scheduleAtFixedRate(new TimerTask() {
@ -378,7 +372,7 @@ public class AndroidGamepadManager {
}
private static void removeDeviceListener() {
if (Build.VERSION.SDK_INT < 16) {
if (Versions.preJB) {
if (sPollTimer != null) {
sPollTimer.cancel();
sPollTimer = null;

View File

@ -8,6 +8,8 @@ package org.mozilla.gecko;
import org.mozilla.gecko.mozglue.RobocopTarget;
import android.os.Build;
/**
* A collection of constants that pertain to the build and runtime state of the
* application. Typically these are sourced from build-time definitions (see
@ -20,12 +22,57 @@ import org.mozilla.gecko.mozglue.RobocopTarget;
@RobocopTarget
public class AppConstants {
public static final String ANDROID_PACKAGE_NAME = "@ANDROID_PACKAGE_NAME@";
// Maintain a separate search package name so that we can speciailize it in the standalone search project
public static final String SEARCH_PACKAGE_NAME = "@ANDROID_PACKAGE_NAME@";
public static final String MANGLED_ANDROID_PACKAGE_NAME = "@MANGLED_ANDROID_PACKAGE_NAME@";
/**
* Encapsulates access to compile-time version definitions, allowing
* for dead code removal for particular APKs.
*/
public static final class Versions {
public static final int MIN_SDK_VERSION = @MOZ_ANDROID_MIN_SDK_VERSION@;
public static final int MAX_SDK_VERSION =
#ifdef MOZ_ANDROID_MAX_SDK_VERSION
@MOZ_ANDROID_MAX_SDK_VERSION@;
#else
999;
#endif
/*
* The SDK_INT >= N check can only pass if our MAX_SDK_VERSION is
* _greater than or equal_ to that number, because otherwise we
* won't be installed on the device.
*
* If MIN_SDK_VERSION is greater than or equal to the number, there
* is no need to do the runtime check.
*/
public static final boolean feature10Plus = MIN_SDK_VERSION >= 10 || (MAX_SDK_VERSION >= 10 && Build.VERSION.SDK_INT >= 10);
public static final boolean feature11Plus = MIN_SDK_VERSION >= 11 || (MAX_SDK_VERSION >= 11 && Build.VERSION.SDK_INT >= 11);
public static final boolean feature12Plus = MIN_SDK_VERSION >= 12 || (MAX_SDK_VERSION >= 12 && Build.VERSION.SDK_INT >= 12);
public static final boolean feature14Plus = MIN_SDK_VERSION >= 14 || (MAX_SDK_VERSION >= 14 && Build.VERSION.SDK_INT >= 14);
public static final boolean feature15Plus = MIN_SDK_VERSION >= 15 || (MAX_SDK_VERSION >= 15 && Build.VERSION.SDK_INT >= 15);
public static final boolean feature16Plus = MIN_SDK_VERSION >= 16 || (MAX_SDK_VERSION >= 16 && Build.VERSION.SDK_INT >= 16);
public static final boolean feature17Plus = MIN_SDK_VERSION >= 17 || (MAX_SDK_VERSION >= 17 && Build.VERSION.SDK_INT >= 17);
public static final boolean feature19Plus = MIN_SDK_VERSION >= 19 || (MAX_SDK_VERSION >= 19 && Build.VERSION.SDK_INT >= 19);
/*
* If our MIN_SDK_VERSION is 14 or higher, we must be an ICS device.
* If our MAX_SDK_VERSION is lower than ICS, we must not be an ICS device.
* Otherwise, we need a range check.
*/
public static final boolean preJB = MAX_SDK_VERSION < 16 || (MIN_SDK_VERSION < 16 && Build.VERSION.SDK_INT < 16);
public static final boolean preICS = MAX_SDK_VERSION < 14 || (MIN_SDK_VERSION < 14 && Build.VERSION.SDK_INT < 14);
public static final boolean preHCMR2 = MAX_SDK_VERSION < 13 || (MIN_SDK_VERSION < 13 && Build.VERSION.SDK_INT < 13);
public static final boolean preHCMR1 = MAX_SDK_VERSION < 12 || (MIN_SDK_VERSION < 12 && Build.VERSION.SDK_INT < 12);
public static final boolean preHC = MAX_SDK_VERSION < 11 || (MIN_SDK_VERSION < 11 && Build.VERSION.SDK_INT < 11);
}
/**
* The name of the Java class that launches the browser.
*/
public static final String BROWSER_INTENT_CLASS_NAME = "org.mozilla.gecko.BrowserApp";
public static final String SEARCH_INTENT_CLASS_NAME = "org.mozilla.search.MainActivity";
public static final String GRE_MILESTONE = "@GRE_MILESTONE@";
@ -140,9 +187,11 @@ public class AppConstants {
false;
#endif
// Android Beam is only supported on API14+, so we don't even bother building
// it if this APK doesn't include API14 support.
public static final boolean MOZ_ANDROID_BEAM =
#ifdef MOZ_ANDROID_BEAM
true;
Versions.feature14Plus;
#else
false;
#endif

View File

@ -5,16 +5,16 @@
package org.mozilla.gecko;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.prompts.PromptService;
import android.app.Activity;
import android.content.Context;
import android.graphics.RectF;
import android.hardware.SensorEventListener;
import android.location.LocationListener;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@ -79,7 +79,7 @@ public class BaseGeckoInterface implements GeckoAppShell.GeckoInterface {
WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
if (Build.VERSION.SDK_INT >= 11) {
if (Versions.feature11Plus) {
window.getDecorView().setSystemUiVisibility(fullscreen ? 1 : 0);
}
}

View File

@ -7,7 +7,6 @@ package org.mozilla.gecko;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.Class;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.EnumSet;
@ -15,11 +14,10 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.DynamicToolbar.PinReason;
import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
@ -53,8 +51,8 @@ import org.mozilla.gecko.home.HomePanelsManager;
import org.mozilla.gecko.home.SearchEngine;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.GeckoMenuItem;
import org.mozilla.gecko.preferences.GeckoPreferences;
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.sync.setup.SyncAccounts;
@ -66,10 +64,10 @@ import org.mozilla.gecko.util.Clipboard;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.MenuUtils;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
import org.mozilla.gecko.util.PrefUtils;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.ThreadUtils;
@ -322,7 +320,7 @@ public class BrowserApp extends GeckoApp
// Check if this was a shortcut. Meta keys exists only on 11+.
final Tab tab = Tabs.getInstance().getSelectedTab();
if (Build.VERSION.SDK_INT >= 11 && tab != null && event.isCtrlPressed()) {
if (Versions.feature11Plus && tab != null && event.isCtrlPressed()) {
switch (keyCode) {
case KeyEvent.KEYCODE_LEFT_BRACKET:
tab.doBack();
@ -556,25 +554,12 @@ public class BrowserApp extends GeckoApp
final SuggestedSites suggestedSites = new SuggestedSites(appContext, distribution);
BrowserDB.setSuggestedSites(suggestedSites);
// Shipping Native casting is optional and dependent on whether you've downloaded the support
// and google play libraries
if (AppConstants.MOZ_MEDIA_PLAYER) {
try {
Class<?> mediaManagerClass = Class.forName("org.mozilla.gecko.MediaPlayerManager");
Method init = mediaManagerClass.getMethod("init", Context.class);
init.invoke(null, this);
} catch(Exception ex) {
// Ignore failures
Log.i(LOGTAG, "No native casting support", ex);
}
}
JavaAddonManager.getInstance().init(appContext);
mSharedPreferencesHelper = new SharedPreferencesHelper(appContext);
mOrderedBroadcastHelper = new OrderedBroadcastHelper(appContext);
mBrowserHealthReporter = new BrowserHealthReporter();
if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 14) {
if (AppConstants.MOZ_ANDROID_BEAM) {
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
if (nfc != null) {
nfc.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
@ -812,7 +797,7 @@ public class BrowserApp extends GeckoApp
if (itemId == R.id.site_settings) {
// This can be selected from either the browser menu or the contextmenu, depending on the size and version (v11+) of the phone.
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Permissions:Get", null));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
if (Versions.preHC) {
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.CONTEXT_MENU, "site_settings");
}
return true;
@ -838,7 +823,7 @@ public class BrowserApp extends GeckoApp
Log.e(LOGTAG, "error building json arguments");
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Feeds:Subscribe", args.toString()));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
if (Versions.preHC) {
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.CONTEXT_MENU, "subscribe");
}
}
@ -858,7 +843,7 @@ public class BrowserApp extends GeckoApp
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Add", args.toString()));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
if (Versions.preHC) {
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.CONTEXT_MENU, "add_search_engine");
}
}
@ -962,7 +947,7 @@ public class BrowserApp extends GeckoApp
"Telemetry:Gather",
"Updater:Launch");
if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 14) {
if (AppConstants.MOZ_ANDROID_BEAM) {
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
if (nfc != null) {
// null this out even though the docs say it's not needed,
@ -2328,7 +2313,7 @@ public class BrowserApp extends GeckoApp
}
// Action providers are available only ICS+.
if (Build.VERSION.SDK_INT >= 14) {
if (Versions.feature14Plus) {
GeckoMenuItem share = (GeckoMenuItem) mMenu.findItem(R.id.share);
GeckoActionProvider provider = GeckoActionProvider.getForType(GeckoActionProvider.DEFAULT_MIME_TYPE, this);
share.setActionProvider(provider);
@ -2409,11 +2394,17 @@ public class BrowserApp extends GeckoApp
MenuItem enterGuestMode = aMenu.findItem(R.id.new_guest_session);
MenuItem exitGuestMode = aMenu.findItem(R.id.exit_guest_session);
// Only show the "Quit" menu item on pre-ICS, television devices, or if the user has explicitly enabled the clear on shutdown pref.
// Only show the "Quit" menu item on pre-ICS, television devices,
// or if the user has explicitly enabled the clear on shutdown pref.
// (We check the pref last to save the pref read.)
// In ICS+, it's easy to kill an app through the task switcher.
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
final Set<String> clearItems = PrefUtils.getStringSet(prefs, ClearOnShutdownPref.PREF, new HashSet<String>());
aMenu.findItem(R.id.quit).setVisible(clearItems.size() > 0 || Build.VERSION.SDK_INT < 14 || HardwareUtils.isTelevision());
final boolean visible = Versions.preICS ||
HardwareUtils.isTelevision() ||
!PrefUtils.getStringSet(GeckoSharedPrefs.forProfile(this),
ClearOnShutdownPref.PREF,
new HashSet<String>()).isEmpty();
aMenu.findItem(R.id.quit).setVisible(visible);
if (tab == null || tab.getURL() == null) {
bookmark.setEnabled(false);
@ -2467,7 +2458,7 @@ public class BrowserApp extends GeckoApp
MenuUtils.safeSetEnabled(aMenu, R.id.add_to_launcher, !isAboutHome(tab));
// Action providers are available only ICS+.
if (Build.VERSION.SDK_INT >= 14) {
if (Versions.feature14Plus) {
final GeckoActionProvider provider = ((GeckoMenuItem) share).getGeckoActionProvider();
if (provider != null) {
Intent shareIntent = provider.getIntent();
@ -2771,7 +2762,7 @@ public class BrowserApp extends GeckoApp
super.onNewIntent(intent);
if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 10 && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
if (AppConstants.MOZ_ANDROID_BEAM && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
String uri = intent.getDataString();
GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(uri));
}

View File

@ -22,10 +22,12 @@ import com.google.android.gms.cast.MediaMetadata;
import com.google.android.gms.cast.MediaStatus;
import com.google.android.gms.cast.RemoteMediaPlayer;
import com.google.android.gms.cast.RemoteMediaPlayer.MediaChannelResult;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.common.GooglePlayServicesUtil;
import android.content.Context;
import android.os.Bundle;
@ -137,6 +139,11 @@ class ChromeCast implements GeckoMediaPlayer {
}
public ChromeCast(Context context, RouteInfo route) {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (status != ConnectionResult.SUCCESS) {
throw new IllegalStateException("Play services are required for Chromecast support (go status code " + status + ")");
}
this.context = context;
this.route = route;
this.canMirror = route.supportsControlCategory(CastMediaControlIntent.categoryForCast(MIRROR_RECIEVER_APP_ID));

View File

@ -14,6 +14,7 @@ import java.util.Map.Entry;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
@ -29,7 +30,6 @@ import android.content.DialogInterface;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
@ -1628,7 +1628,8 @@ public class ContactService implements GeckoEventListener {
private static boolean isAutoAddGroup(Cursor cursor) {
// For Honeycomb and up, the default group is the first one which has the AUTO_ADD flag set.
// For everything below Honeycomb, use the default "System Group: My Contacts" group
return (Build.VERSION.SDK_INT >= 11 && !cursor.isNull(GROUP_AUTO_ADD) &&
return (Versions.feature11Plus &&
!cursor.isNull(GROUP_AUTO_ADD) &&
cursor.getInt(GROUP_AUTO_ADD) != 0);
}
@ -1681,7 +1682,7 @@ public class ContactService implements GeckoEventListener {
Groups.ACCOUNT_TYPE,
Groups._ID,
Groups.TITLE,
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Groups.AUTO_ADD : Groups._ID)
(Versions.feature11Plus ? Groups.AUTO_ADD : Groups._ID)
};
if (selectArg != null) {

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.preferences.GeckoPreferences;
import android.app.Notification;
@ -15,7 +16,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.text.Spannable;
import android.text.SpannableString;
@ -87,7 +87,7 @@ public class DataReportingNotification {
// Create and send notification.
String notificationTitle = resources.getString(R.string.datareporting_notification_title);
String notificationSummary;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
if (Versions.preJB) {
notificationSummary = resources.getString(R.string.datareporting_notification_action);
} else {
// Display partial version of Big Style notification for supporting devices.

View File

@ -5,25 +5,24 @@
package org.mozilla.gecko;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.ArrowPopup;
import org.mozilla.gecko.widget.DoorHanger;
import org.mozilla.gecko.prompts.PromptInput;
import java.util.HashSet;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.prompts.PromptInput;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.ArrowPopup;
import org.mozilla.gecko.widget.DoorHanger;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import java.util.HashSet;
import java.util.List;
public class DoorHangerPopup extends ArrowPopup
implements GeckoEventListener,
Tabs.OnTabsChangedListener,
@ -311,13 +310,13 @@ public class DoorHangerPopup extends ArrowPopup
// Make the popup focusable for accessibility. This gets done here
// so the node can be accessibility focused, but on pre-ICS devices this
// causes crashes, so it is done after the popup is shown.
if (Build.VERSION.SDK_INT >= 14) {
if (Versions.feature14Plus) {
setFocusable(true);
}
show();
if (Build.VERSION.SDK_INT < 14) {
if (Versions.preICS) {
// Make the popup focusable for keyboard accessibility.
setFocusable(true);
}

View File

@ -5,19 +5,22 @@
package org.mozilla.gecko;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
@ -29,10 +32,6 @@ import android.view.accessibility.AccessibilityNodeProvider;
import com.googlecode.eyesfree.braille.selfbraille.SelfBrailleClient;
import com.googlecode.eyesfree.braille.selfbraille.WriteData;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
public class GeckoAccessibility {
private static final String LOGTAG = "GeckoAccessibility";
private static final int VIRTUAL_CURSOR_PREVIOUS = 1;
@ -74,8 +73,7 @@ public class GeckoAccessibility {
if (sEnabled)
break;
}
if (sEnabled && sSelfBrailleClient == null &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (Versions.feature16Plus && sEnabled && sSelfBrailleClient == null) {
sSelfBrailleClient = new SelfBrailleClient(GeckoAppShell.getContext(), false);
}
}
@ -117,13 +115,13 @@ public class GeckoAccessibility {
event.setItemCount(message.optInt("itemCount", -1));
event.setCurrentItemIndex(message.optInt("currentItemIndex", -1));
event.setBeforeText(message.optString("beforeText"));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (Versions.feature14Plus) {
event.setToIndex(message.optInt("toIndex", -1));
event.setScrollable(message.optBoolean("scrollable"));
event.setScrollX(message.optInt("scrollX", -1));
event.setScrollY(message.optInt("scrollY", -1));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
if (Versions.feature15Plus) {
event.setMaxScrollX(message.optInt("maxScrollX", -1));
event.setMaxScrollY(message.optInt("maxScrollY", -1));
}
@ -153,7 +151,7 @@ public class GeckoAccessibility {
return;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
if (Versions.preJB) {
// Before Jelly Bean we send events directly from here while spoofing the source by setting
// the package and class name manually.
ThreadUtils.postToBackgroundThread(new Runnable() {
@ -247,7 +245,7 @@ public class GeckoAccessibility {
public static void setDelegate(LayerView layerview) {
// Only use this delegate in Jelly Bean.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (Versions.feature16Plus) {
layerview.setAccessibilityDelegate(new GeckoAccessibilityDelegate());
layerview.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}

View File

@ -26,6 +26,7 @@ import java.util.regex.Pattern;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.favicons.Favicons;
@ -78,7 +79,6 @@ import android.hardware.SensorEventListener;
import android.location.Location;
import android.location.LocationListener;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
@ -295,13 +295,15 @@ public abstract class GeckoApp
@Override
public void invalidateOptionsMenu() {
if (mMenu == null)
if (mMenu == null) {
return;
}
onPrepareOptionsMenu(mMenu);
if (Build.VERSION.SDK_INT >= 11)
if (Versions.feature11Plus) {
super.invalidateOptionsMenu();
}
}
@Override
@ -315,10 +317,11 @@ public abstract class GeckoApp
@Override
public MenuInflater getMenuInflater() {
if (Build.VERSION.SDK_INT >= 11)
if (Versions.feature11Plus) {
return new GeckoMenuInflater(this);
else
} else {
return super.getMenuInflater();
}
}
public MenuPanel getMenuPanel() {
@ -369,7 +372,7 @@ public abstract class GeckoApp
@Override
public View onCreatePanelView(int featureId) {
if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) {
if (Versions.feature11Plus && featureId == Window.FEATURE_OPTIONS_PANEL) {
if (mMenuPanel == null) {
mMenuPanel = new MenuPanel(this, null);
} else {
@ -385,7 +388,7 @@ public abstract class GeckoApp
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) {
if (Versions.feature11Plus && featureId == Window.FEATURE_OPTIONS_PANEL) {
if (mMenuPanel == null) {
mMenuPanel = (MenuPanel) onCreatePanelView(featureId);
}
@ -404,8 +407,9 @@ public abstract class GeckoApp
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL)
if (Versions.feature11Plus && featureId == Window.FEATURE_OPTIONS_PANEL) {
return onPrepareOptionsMenu(menu);
}
return super.onPreparePanel(featureId, view, menu);
}
@ -417,7 +421,7 @@ public abstract class GeckoApp
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FullScreen:Exit", null));
}
if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) {
if (Versions.feature11Plus && featureId == Window.FEATURE_OPTIONS_PANEL) {
if (mMenu == null) {
// getMenuPanel() will force the creation of the menu as well
MenuPanel panel = getMenuPanel();
@ -463,7 +467,7 @@ public abstract class GeckoApp
@Override
public void onOptionsMenuClosed(Menu menu) {
if (Build.VERSION.SDK_INT >= 11) {
if (Versions.feature11Plus) {
mMenuPanel.removeAllViews();
mMenuPanel.addView((GeckoMenu) mMenu);
}
@ -1049,8 +1053,9 @@ public abstract class GeckoApp
WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
if (Build.VERSION.SDK_INT >= 11)
if (Versions.feature11Plus) {
window.getDecorView().setSystemUiVisibility(fullscreen ? 1 : 0);
}
}
});
}
@ -1341,7 +1346,7 @@ public abstract class GeckoApp
if (mCameraView == null) {
// Pre-ICS devices need the camera surface in a visible layout.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (Versions.preICS) {
mCameraView = new SurfaceView(this);
((SurfaceView)mCameraView).getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@ -1737,7 +1742,7 @@ public abstract class GeckoApp
// Try to make it fully transparent.
if (mCameraView != null && (mCameraView instanceof SurfaceView)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (Versions.feature11Plus) {
mCameraView.setAlpha(0.0f);
}
ViewGroup mCameraLayout = (ViewGroup) findViewById(R.id.camera_layout);
@ -2577,7 +2582,7 @@ public abstract class GeckoApp
}
private void setSystemUiVisible(final boolean visible) {
if (Build.VERSION.SDK_INT < 14) {
if (Versions.preICS) {
return;
}

View File

@ -32,6 +32,7 @@ import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
import org.mozilla.gecko.gfx.BitmapUtils;
@ -88,7 +89,6 @@ import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
@ -832,7 +832,7 @@ public class GeckoAppShell
@JNITarget
static public int getPreferredIconSize() {
if (android.os.Build.VERSION.SDK_INT >= 11) {
if (Versions.feature11Plus) {
ActivityManager am = (ActivityManager)getContext().getSystemService(Context.ACTIVITY_SERVICE);
return am.getLauncherLargeIconSize();
} else {
@ -1829,7 +1829,7 @@ public class GeckoAppShell
}
// disable on KitKat (bug 957694)
if (Build.VERSION.SDK_INT >= 19) {
if (Versions.feature19Plus) {
Log.w(LOGTAG, "Blocking plugins because of Tegra (bug 957694)");
return null;
}

View File

@ -5,15 +5,22 @@
package org.mozilla.gecko;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.gfx.InputConnectionHandler;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
import org.json.JSONObject;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
@ -30,14 +37,6 @@ import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
// interface for the IC thread
interface GeckoEditableClient {
void sendEvent(GeckoEvent event);
@ -251,8 +250,8 @@ final class GeckoEditable
try {
if (mKeyMap == null) {
mKeyMap = KeyCharacterMap.load(
Build.VERSION.SDK_INT < 11 ? KeyCharacterMap.ALPHA :
KeyCharacterMap.VIRTUAL_KEYBOARD);
Versions.preHC ? KeyCharacterMap.ALPHA :
KeyCharacterMap.VIRTUAL_KEYBOARD);
}
} catch (Exception e) {
// KeyCharacterMap.UnavailableExcepton is not found on Gingerbread;
@ -488,8 +487,9 @@ final class GeckoEditable
}
int tpUnderlineColor = 0;
float tpUnderlineThickness = 0.0f;
// These TextPaint fields only exist on Android ICS+ and are not in the SDK
if (Build.VERSION.SDK_INT >= 14) {
// These TextPaint fields only exist on Android ICS+ and are not in the SDK.
if (Versions.feature14Plus) {
tpUnderlineColor = (Integer)getField(tp, "underlineColor", 0);
tpUnderlineThickness = (Float)getField(tp, "underlineThickness", 0.0f);
}

View File

@ -5,14 +5,17 @@
package org.mozilla.gecko;
import java.nio.ByteBuffer;
import java.util.concurrent.ArrayBlockingQueue;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.gfx.DisplayPortMetrics;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.mozglue.JNITarget;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions;
import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
import org.mozilla.gecko.mozglue.RobocopTarget;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@ -21,17 +24,12 @@ import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.location.Address;
import android.location.Location;
import android.os.Build;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.MotionEvent;
import java.nio.ByteBuffer;
import java.util.concurrent.ArrayBlockingQueue;
/* We're not allowed to hold on to most events given to us
* so we save the parts of the events we want to use in GeckoEvent.
* Fields have different meanings depending on the event type.
@ -331,7 +329,7 @@ public class GeckoEvent {
case KeyEvent.KEYCODE_DPAD_UP:
return true;
default:
if (Build.VERSION.SDK_INT >= 12) {
if (Versions.feature12Plus) {
return KeyEvent.isGamepadButton(keyCode);
}
return GeckoEvent.isGamepadButton(keyCode);
@ -340,7 +338,7 @@ public class GeckoEvent {
/**
* This method is a replacement for the the KeyEvent.isGamepadButton method to be
* compatible with Build.VERSION.SDK_INT < 12. This is an implementantion of the
* compatible with Build.VERSION.SDK_INT < 12. This is an implementation of the
* same method isGamepadButton available after SDK 12.
* @param keyCode int with the key code (Android key constant from KeyEvent).
* @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}.

View File

@ -10,6 +10,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.SynchronousQueue;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.gfx.InputConnectionHandler;
import org.mozilla.gecko.util.Clipboard;
import org.mozilla.gecko.util.GamepadUtils;
@ -18,7 +19,6 @@ import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
import android.R;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
@ -953,10 +953,10 @@ class GeckoInputConnection
if (typeHint != null &&
(typeHint.equalsIgnoreCase("date") ||
typeHint.equalsIgnoreCase("time") ||
(Build.VERSION.SDK_INT >= 11 && (typeHint.equalsIgnoreCase("datetime") ||
typeHint.equalsIgnoreCase("month") ||
typeHint.equalsIgnoreCase("week") ||
typeHint.equalsIgnoreCase("datetime-local"))))) {
(Versions.feature11Plus && (typeHint.equalsIgnoreCase("datetime") ||
typeHint.equalsIgnoreCase("month") ||
typeHint.equalsIgnoreCase("week") ||
typeHint.equalsIgnoreCase("datetime-local"))))) {
state = IME_STATE_DISABLED;
}

View File

@ -5,17 +5,15 @@
package org.mozilla.gecko;
import org.mozilla.gecko.mozglue.RobocopTarget;
import java.util.Collection;
import org.mozilla.gecko.AppConstants.Versions;
import android.content.Context;
import android.os.Build;
import android.provider.Settings.Secure;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import java.util.Collection;
import java.util.Locale;
final public class InputMethods {
public static final String METHOD_ANDROID_LATINIME = "com.android.inputmethod.latin/.LatinIME";
public static final String METHOD_ATOK = "com.justsystems.atokmobile.service/.AtokInputMethodService";
@ -55,8 +53,9 @@ final public class InputMethods {
public static boolean needsSoftResetWorkaround(String inputMethod) {
// Stock latin IME on Android 4.2 and above
return Build.VERSION.SDK_INT >= 17 && (METHOD_ANDROID_LATINIME.equals(inputMethod) ||
METHOD_GOOGLE_LATINIME.equals(inputMethod));
return Versions.feature17Plus &&
(METHOD_ANDROID_LATINIME.equals(inputMethod) ||
METHOD_GOOGLE_LATINIME.equals(inputMethod));
}
public static boolean shouldCommitCharAsKey(String inputMethod) {
@ -67,8 +66,9 @@ final public class InputMethods {
// SwiftKey is a gesture keyboard, but it doesn't seem to need any special-casing
// to do AwesomeBar auto-spacing.
String inputMethod = getCurrentInputMethod(context);
return (Build.VERSION.SDK_INT >= 17 && (METHOD_ANDROID_LATINIME.equals(inputMethod) ||
METHOD_GOOGLE_LATINIME.equals(inputMethod))) ||
return (Versions.feature17Plus &&
(METHOD_ANDROID_LATINIME.equals(inputMethod) ||
METHOD_GOOGLE_LATINIME.equals(inputMethod))) ||
METHOD_SWYPE.equals(inputMethod) ||
METHOD_SWYPE_BETA.equals(inputMethod) ||
METHOD_TOUCHPAL_KEYBOARD.equals(inputMethod);

View File

@ -5,11 +5,15 @@
package org.mozilla.gecko;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
import org.json.JSONObject;
import android.app.Application;
import android.graphics.Bitmap;
@ -19,7 +23,6 @@ import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
@ -28,9 +31,6 @@ import android.view.Gravity;
import android.view.View;
import android.view.ViewParent;
import java.util.ArrayList;
import java.util.List;
public class LightweightTheme implements GeckoEventListener {
private static final String LOGTAG = "GeckoLightweightTheme";
@ -253,7 +253,7 @@ public class LightweightTheme implements GeckoEventListener {
ViewParent parent;
View curView = view;
do {
if (Build.VERSION.SDK_INT >= 11) {
if (Versions.feature11Plus) {
offsetX += (int) curView.getTranslationX() - curView.getScrollX();
offsetY += (int) curView.getTranslationY() - curView.getScrollY();
} else {

View File

@ -6,6 +6,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.mozglue.JNITarget;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
@ -41,7 +42,7 @@ interface GeckoMediaPlayer {
* from Gecko to the correct caster based on the id of the display
*/
class MediaPlayerManager implements NativeEventListener,
GeckoAppShell.AppStateListener {
GeckoAppShell.AppStateListener {
private static final String LOGTAG = "GeckoMediaPlayerManager";
private static final boolean SHOW_DEBUG = false;
@ -63,9 +64,11 @@ class MediaPlayerManager implements NativeEventListener,
private final HashMap<String, GeckoMediaPlayer> displays = new HashMap<String, GeckoMediaPlayer>();
private static MediaPlayerManager instance;
@JNITarget
public static void init(Context context) {
if (instance != null) {
debug("MediaPlayerManager initialized twice");
return;
}
instance = new MediaPlayerManager(context);
@ -92,6 +95,7 @@ class MediaPlayerManager implements NativeEventListener,
"MediaPlayer:Message");
}
@JNITarget
public static void onDestroy() {
if (instance == null) {
return;

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.favicons.Favicons;
@ -15,7 +16,6 @@ import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.util.Log;
/**
@ -89,8 +89,8 @@ class MemoryMonitor extends BroadcastReceiver {
public void onTrimMemory(int level) {
Log.d(LOGTAG, "onTrimMemory() notification received with level " + level);
if (Build.VERSION.SDK_INT < 14) {
// this won't even get called pre-ICS
if (Versions.preICS) {
// This won't even get called pre-ICS.
return;
}

View File

@ -5,18 +5,19 @@
package org.mozilla.gecko.animation;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import org.mozilla.gecko.AppConstants.Versions;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
class AnimatorProxy {
private static final WeakHashMap<View, AnimatorProxy> PROXIES =
new WeakHashMap<View, AnimatorProxy>();
@ -42,7 +43,7 @@ class AnimatorProxy {
public static AnimatorProxy create(View view) {
AnimatorProxy proxy = PROXIES.get(view);
boolean needsAnimationProxy = (Build.VERSION.SDK_INT < 11);
final boolean needsAnimationProxy = Versions.preHC;
// If the view's animation proxy has been overridden from somewhere else, we need to
// create a new AnimatorProxy for the view.

View File

@ -5,9 +5,13 @@
package org.mozilla.gecko.animation;
import android.support.v4.view.ViewCompat;
import android.os.Build;
import java.util.ArrayList;
import java.util.List;
import org.mozilla.gecko.AppConstants.Versions;
import android.os.Handler;
import android.support.v4.view.ViewCompat;
import android.view.Choreographer;
import android.view.View;
import android.view.ViewGroup;
@ -16,9 +20,6 @@ import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import java.util.ArrayList;
import java.util.List;
public class PropertyAnimator implements Runnable {
private static final String LOGTAG = "GeckoPropertyAnimator";
@ -163,7 +164,7 @@ public class PropertyAnimator implements Runnable {
// in the current view tree. OnPreDrawListener seems broken
// on pre-Honeycomb devices, start animation immediatelly
// in this case.
if (Build.VERSION.SDK_INT >= 11 && treeObserver != null && treeObserver.isAlive()) {
if (Versions.feature11Plus && treeObserver != null && treeObserver.isAlive()) {
treeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
@ -186,7 +187,6 @@ public class PropertyAnimator implements Runnable {
}
}
/**
* Stop the animation, optionally snapping to the end position.
* onPropertyAnimationEnd is only called when snapping to the end position.
@ -201,10 +201,11 @@ public class PropertyAnimator implements Runnable {
ViewCompat.setHasTransientState(element.view, false);
if (shouldEnableHardwareLayer(element))
if (shouldEnableHardwareLayer(element)) {
element.view.setLayerType(View.LAYER_TYPE_NONE, null);
else
} else {
element.view.setDrawingCacheEnabled(false);
}
}
mElementsList.clear();
@ -226,19 +227,23 @@ public class PropertyAnimator implements Runnable {
}
private boolean shouldEnableHardwareLayer(ElementHolder element) {
if (!mUseHardwareLayer)
if (Versions.preHC) {
return false;
}
if (Build.VERSION.SDK_INT < 11)
if (!mUseHardwareLayer) {
return false;
}
if (!(element.view instanceof ViewGroup))
if (!(element.view instanceof ViewGroup)) {
return false;
}
if (element.property == Property.ALPHA ||
element.property == Property.TRANSLATION_Y ||
element.property == Property.TRANSLATION_X)
element.property == Property.TRANSLATION_X) {
return true;
}
return false;
}
@ -269,10 +274,11 @@ public class PropertyAnimator implements Runnable {
private static abstract class FramePoster {
public static FramePoster create(Runnable r) {
if (Build.VERSION.SDK_INT >= 16)
if (Versions.feature16Plus) {
return new FramePosterPostJB(r);
else
return new FramePosterPreJB(r);
}
return new FramePosterPreJB(r);
}
public abstract void postFirstAnimationFrame();
@ -284,8 +290,8 @@ public class PropertyAnimator implements Runnable {
// Default refresh rate in ms.
private static final int INTERVAL = 10;
private Handler mHandler;
private Runnable mRunnable;
private final Handler mHandler;
private final Runnable mRunnable;
public FramePosterPreJB(Runnable r) {
mHandler = new Handler();
@ -309,8 +315,8 @@ public class PropertyAnimator implements Runnable {
}
private static class FramePosterPostJB extends FramePoster {
private Choreographer mChoreographer;
private Choreographer.FrameCallback mCallback;
private final Choreographer mChoreographer;
private final Choreographer.FrameCallback mCallback;
public FramePosterPostJB(final Runnable r) {
mChoreographer = Choreographer.getInstance();

View File

@ -4,12 +4,13 @@
package org.mozilla.gecko.db;
import org.mozilla.gecko.AppConstants.Versions;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
@ -94,7 +95,7 @@ public abstract class AbstractTransactionalProvider extends ContentProvider {
*/
@SuppressWarnings("static-method")
protected boolean shouldUseTransactions() {
return Build.VERSION.SDK_INT >= 11;
return Versions.feature11Plus;
}
private boolean isInBatch() {

View File

@ -4,11 +4,11 @@
package org.mozilla.gecko.db;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.db.PerProfileDatabases.DatabaseHelperFactory;
import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
/**
* Abstract class containing methods needed to make a SQLite-based content
@ -42,7 +42,7 @@ public abstract class PerProfileDatabaseProvider<T extends SQLiteOpenHelper> ext
@Override
public T makeDatabaseHelper(Context context, String databasePath) {
final T helper = createDatabaseHelper(context, databasePath);
if (Build.VERSION.SDK_INT >= 16) {
if (Versions.feature16Plus) {
helper.setWriteAheadLoggingEnabled(true);
}
return helper;

View File

@ -4,6 +4,7 @@
package org.mozilla.gecko.db;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.db.BrowserContract.CommonColumns;
import org.mozilla.gecko.db.BrowserContract.SyncColumns;
import org.mozilla.gecko.db.PerProfileDatabases.DatabaseHelperFactory;
@ -12,7 +13,6 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
/**
@ -50,7 +50,7 @@ public abstract class SharedBrowserDatabaseProvider extends AbstractPerProfileDa
@Override
public BrowserDatabaseHelper makeDatabaseHelper(Context context, String databasePath) {
final BrowserDatabaseHelper helper = new BrowserDatabaseHelper(context, databasePath);
if (Build.VERSION.SDK_INT >= 16) {
if (Versions.feature16Plus) {
helper.setWriteAheadLoggingEnabled(true);
}
return helper;

View File

@ -8,6 +8,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.db.BrowserContract.Clients;
import org.mozilla.gecko.db.BrowserContract.Tabs;
@ -171,7 +172,7 @@ public class TabsProvider extends PerProfileDatabaseProvider<TabsProvider.TabsDa
if (shouldUseTransactions()) {
// Modern Android allows WAL to be enabled through a mode flag.
if (Build.VERSION.SDK_INT < 16) {
if (Versions.preJB) {
db.enableWriteAheadLogging();
}
db.setLockingEnabled(false);

View File

@ -5,23 +5,22 @@
package org.mozilla.gecko.gfx;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.ZoomConstraints;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.util.FloatUtils;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONObject;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Build;
import android.util.FloatMath;
import android.util.Log;
import android.view.GestureDetector;
@ -294,7 +293,7 @@ class JavaPanZoomController
/** This function MUST be called on the UI thread */
@Override
public boolean onKeyEvent(KeyEvent event) {
if (Build.VERSION.SDK_INT <= 11) {
if (Versions.preHCMR1) {
return false;
}
@ -314,7 +313,7 @@ class JavaPanZoomController
/** This function MUST be called on the UI thread */
@Override
public boolean onMotionEvent(MotionEvent event) {
if (Build.VERSION.SDK_INT <= 11) {
if (Versions.preHCMR1) {
return false;
}

View File

@ -9,6 +9,7 @@ import java.nio.IntBuffer;
import java.util.ArrayList;
import org.mozilla.gecko.AndroidGamepadManager;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAccessibility;
import org.mozilla.gecko.GeckoAppShell;
@ -30,7 +31,6 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
@ -110,7 +110,7 @@ public class LayerView extends FrameLayout implements Tabs.OnTabsChangedListener
mFullScreenState = FullScreenState.NONE;
mTouchInterceptors = new ArrayList<TouchEventInterceptor>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (Versions.feature14Plus) {
mOverscroll = new OverscrollEdgeEffect(this);
} else {
mOverscroll = null;

View File

@ -5,11 +5,12 @@
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.AppConstants.Versions;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.widget.EdgeEffect;
import android.view.View;
import android.widget.EdgeEffect;
public class OverscrollEdgeEffect implements Overscroll {
@ -57,7 +58,7 @@ public class OverscrollEdgeEffect implements Overscroll {
}
private void invalidate() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (Versions.feature16Plus) {
mView.postInvalidateOnAnimation();
} else {
mView.postInvalidateDelayed(10);
@ -118,7 +119,7 @@ public class OverscrollEdgeEffect implements Overscroll {
}
}
public boolean draw(final EdgeEffect edge, final Canvas canvas, final float translateX, final float translateY, final float rotation) {
private static boolean draw(final EdgeEffect edge, final Canvas canvas, final float translateX, final float translateY, final float rotation) {
final int state = canvas.save();
canvas.translate(translateX, translateY);
canvas.rotate(rotation);

View File

@ -5,8 +5,8 @@
package org.mozilla.gecko.home;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
@ -21,19 +21,15 @@ import org.mozilla.gecko.widget.EllipsisTextView;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class HomeBanner extends LinearLayout
implements GeckoEventListener {
@ -133,7 +129,7 @@ public class HomeBanner extends LinearLayout
public void setVisibility(int visibility) {
// On pre-Honeycomb devices, setting the visibility to GONE won't actually
// hide the view unless we clear animations first.
if (Build.VERSION.SDK_INT < 11 && visibility == View.GONE) {
if (Versions.preHC && visibility == View.GONE) {
clearAnimation();
}

View File

@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
@ -20,7 +21,6 @@ import org.mozilla.gecko.util.ThreadUtils;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.LoaderManager;
@ -197,7 +197,7 @@ public class HomePager extends ViewPager {
}
// Only animate on post-HC devices, when a non-null animator is given
final boolean shouldAnimate = (animator != null && Build.VERSION.SDK_INT >= 11);
final boolean shouldAnimate = Versions.feature11Plus && animator != null;
final HomeAdapter adapter = new HomeAdapter(mContext, fm);
adapter.setOnAddPanelListener(mAddPanelListener);

View File

@ -4,15 +4,16 @@
package org.mozilla.gecko.menu;
import org.mozilla.gecko.R;
import java.io.IOException;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.InflateException;
@ -21,18 +22,14 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import java.io.IOException;
public class GeckoMenuInflater extends MenuInflater {
private static final String LOGTAG = "GeckoMenuInflater";
public class GeckoMenuInflater extends MenuInflater {
private static final String TAG_MENU = "menu";
private static final String TAG_ITEM = "item";
private static final int NO_ID = 0;
private Context mContext;
private final Context mContext;
// Private class to hold the parsed menu item.
// Private class to hold the parsed menu item.
private class ParsedItem {
public int id;
public int order;
@ -73,16 +70,16 @@ public class GeckoMenuInflater extends MenuInflater {
}
}
private void parseMenu(XmlResourceParser parser, AttributeSet attrs, Menu menu)
private void parseMenu(XmlResourceParser parser, AttributeSet attrs, Menu menu)
throws XmlPullParserException, IOException {
ParsedItem item = null;
String tag;
int eventType = parser.getEventType();
do {
tag = parser.getName();
switch (eventType) {
case XmlPullParser.START_TAG:
if (tag.equals(TAG_ITEM)) {
@ -136,12 +133,13 @@ public class GeckoMenuInflater extends MenuInflater {
item.enabled = a.getBoolean(R.styleable.MenuItem_android_enabled, true);
item.hasSubMenu = false;
if (Build.VERSION.SDK_INT >= 11)
if (Versions.feature11Plus) {
item.showAsAction = a.getInt(R.styleable.MenuItem_android_showAsAction, 0);
}
a.recycle();
}
public void setValues(ParsedItem item, MenuItem menuItem) {
menuItem.setChecked(item.checked)
.setVisible(item.visible)
@ -149,7 +147,8 @@ public class GeckoMenuInflater extends MenuInflater {
.setCheckable(item.checkable)
.setIcon(item.iconRes);
if (Build.VERSION.SDK_INT >= 11)
if (Versions.feature11Plus) {
menuItem.setShowAsAction(item.showAsAction);
}
}
}

View File

@ -4,12 +4,12 @@
package org.mozilla.gecko.menu;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import org.mozilla.gecko.widget.GeckoActionProvider;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.ActionProvider;
import android.view.ContextMenu;
import android.view.MenuItem;
@ -17,13 +17,11 @@ import android.view.SubMenu;
import android.view.View;
public class GeckoMenuItem implements MenuItem {
private static final String LOGTAG = "GeckoMenuItem";
public static final int SHOW_AS_ACTION_NEVER = 0;
public static final int SHOW_AS_ACTION_IF_ROOM = 1;
public static final int SHOW_AS_ACTION_ALWAYS = 2;
// A View that can show a MenuItem should be able to initialize from
// A View that can show a MenuItem should be able to initialize from
// the properties of the MenuItem.
public static interface Layout {
public void initialize(GeckoMenuItem item);
@ -35,8 +33,8 @@ public class GeckoMenuItem implements MenuItem {
public void onShowAsActionChanged(GeckoMenuItem item);
}
private int mId;
private int mOrder;
private final int mId;
private final int mOrder;
private View mActionView;
private int mActionEnum;
private CharSequence mTitle;
@ -48,7 +46,7 @@ public class GeckoMenuItem implements MenuItem {
private Drawable mIcon;
private int mIconRes;
private GeckoActionProvider mActionProvider;
private GeckoMenu mMenu;
private final GeckoMenu mMenu;
private GeckoSubMenu mSubMenu;
private MenuItem.OnMenuItemClickListener mMenuItemClickListener = null;
private OnShowAsActionChangedListener mShowAsActionChangedListener;
@ -78,7 +76,7 @@ public class GeckoMenuItem implements MenuItem {
}
public boolean hasActionProvider() {
if (Build.VERSION.SDK_INT < 14) {
if (Versions.preICS) {
return false;
}

View File

@ -8,6 +8,7 @@ package org.mozilla.gecko.menu;
import java.util.ArrayList;
import java.util.List;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import android.annotation.TargetApi;
@ -18,17 +19,14 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.os.Build;
public class MenuItemActionView extends LinearLayout
implements GeckoMenuItem.Layout,
View.OnClickListener {
private static final String LOGTAG = "GeckoMenuItemActionView";
private MenuItemDefault mMenuItem;
private MenuItemActionBar mMenuButton;
private List<ImageButton> mActionButtons;
private List<View.OnClickListener> mActionButtonListeners = new ArrayList<View.OnClickListener>();
private final MenuItemDefault mMenuItem;
private final MenuItemActionBar mMenuButton;
private final List<ImageButton> mActionButtons;
private final List<View.OnClickListener> mActionButtonListeners = new ArrayList<View.OnClickListener>();
public MenuItemActionView(Context context) {
this(context, null);
@ -43,12 +41,12 @@ public class MenuItemActionView extends LinearLayout
super(context, attrs);
// Set these explicitly, since setting a style isn't supported for LinearLayouts until V11.
if (Build.VERSION.SDK_INT >= 11) {
if (Versions.feature11Plus) {
setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
setDividerDrawable(getResources().getDrawable(R.drawable.divider_vertical));
}
if (Build.VERSION.SDK_INT >= 14) {
if (Versions.feature14Plus) {
setDividerPadding(0);
}
@ -78,8 +76,9 @@ public class MenuItemActionView extends LinearLayout
@Override
public void initialize(GeckoMenuItem item) {
if (item == null)
if (item == null) {
return;
}
mMenuItem.initialize(item);
mMenuButton.initialize(item);

View File

@ -5,10 +5,10 @@
package org.mozilla.gecko.menu;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
@ -41,8 +41,10 @@ public class MenuPanel extends LinearLayout {
@Override
public boolean dispatchPopulateAccessibilityEvent (AccessibilityEvent event) {
if (Build.VERSION.SDK_INT >= 14) // Build.VERSION_CODES.ICE_CREAM_SANDWICH
if (Versions.feature14Plus) {
onPopulateAccessibilityEvent(event);
}
return true;
}
}

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko.preferences;
import java.util.Locale;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.BrowserLocaleManager;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.LocaleManager;
@ -18,7 +19,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
@ -108,7 +108,7 @@ public class GeckoPreferenceFragment extends PreferenceFragment {
}
final PreferenceActivity activity = (PreferenceActivity) getActivity();
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) && activity.isMultiPane()) {
if (Versions.feature11Plus && activity.isMultiPane()) {
// In a multi-pane activity, the title is "Settings", and the action
// bar is along the top of the screen. We don't want to change those.
activity.showBreadCrumbs(newTitle, newTitle);
@ -118,7 +118,7 @@ public class GeckoPreferenceFragment extends PreferenceFragment {
Log.v(LOGTAG, "Setting activity title to " + newTitle);
activity.setTitle(newTitle);
if (Build.VERSION.SDK_INT >= 14) {
if (Versions.feature14Plus) {
final ActionBar actionBar = activity.getActionBar();
if (actionBar != null) {
actionBar.setTitle(newTitle);
@ -175,7 +175,7 @@ public class GeckoPreferenceFragment extends PreferenceFragment {
// The resource was invalid. Use the default resource.
Log.e(LOGTAG, "Failed to find resource: " + resourceName + ". Displaying default settings.");
boolean isMultiPane = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) &&
boolean isMultiPane = Versions.feature11Plus &&
((PreferenceActivity) activity).isMultiPane();
resid = isMultiPane ? R.xml.preferences_customize_tablet : R.xml.preferences;
}

View File

@ -13,6 +13,7 @@ import java.util.Map;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.BrowserLocaleManager;
import org.mozilla.gecko.DataReportingNotification;
@ -52,7 +53,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
@ -153,7 +153,7 @@ OnSharedPreferenceChangeListener
}
}
private void updateActionBarTitle(int title) {
if (Build.VERSION.SDK_INT >= 14) {
if (Versions.feature14Plus) {
final String newTitle = getString(title);
if (newTitle != null) {
Log.v(LOGTAG, "Setting action bar title to " + newTitle);
@ -190,7 +190,7 @@ OnSharedPreferenceChangeListener
// If we're a multi-pane view, the activity title is really
// the header bar above the fragment.
// Find out which fragment we're showing, and use that.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && isMultiPane()) {
if (Versions.feature11Plus && isMultiPane()) {
int title = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, -1);
if (res == R.xml.preferences) {
// This should only occur when res == R.xml.preferences,
@ -227,7 +227,7 @@ OnSharedPreferenceChangeListener
BrowserLocaleManager.getInstance().updateConfiguration(getApplicationContext(), newLocale);
this.lastLocale = newLocale;
if (Build.VERSION.SDK_INT >= 11 && isMultiPane()) {
if (Versions.feature11Plus && isMultiPane()) {
// This takes care of the left pane.
invalidateHeaders();
@ -301,7 +301,7 @@ OnSharedPreferenceChangeListener
// (or set it) before super.onCreate() is called so Android can display
// the correct Fragment resource.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (Versions.feature11Plus) {
if (!getIntent().hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) {
// Set up the default fragment if there is no explicit fragment to show.
setupTopLevelFragmentIntent();
@ -316,7 +316,7 @@ OnSharedPreferenceChangeListener
// all) in the action bar.
updateActionBarTitle(R.string.settings_title);
if (Build.VERSION.SDK_INT < 13) {
if (android.os.Build.VERSION.SDK_INT < 13) {
// Affected by Bug 1015209 -- no detach/attach.
// If we try rejigging fragments, we'll crash, so don't
// enable locale switching at all.
@ -333,7 +333,7 @@ OnSharedPreferenceChangeListener
// For versions of Android lower than Honeycomb, use xml resources instead of
// Fragments because of an Android bug in ActionBar (described in bug 866352 and
// fixed in bug 833625).
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
if (Versions.preHC) {
// Write prefs to our custom GeckoSharedPrefs file.
getPreferenceManager().setSharedPreferencesName(GeckoSharedPrefs.APP_PREFS_NAME);
@ -381,7 +381,7 @@ OnSharedPreferenceChangeListener
}
});
if (Build.VERSION.SDK_INT >= 14) {
if (Versions.feature14Plus) {
final ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setHomeButtonEnabled(true);
@ -455,7 +455,7 @@ OnSharedPreferenceChangeListener
return;
mInitialized = true;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
if (Versions.preHC) {
PreferenceScreen screen = getPreferenceScreen();
mPrefsRequestId = setupPreferences(screen);
}
@ -483,7 +483,7 @@ OnSharedPreferenceChangeListener
@Override
public void onPause() {
// Symmetric with onResume.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (Versions.feature11Plus) {
if (isMultiPane()) {
SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
prefs.unregisterOnSharedPreferenceChangeListener(this);
@ -505,7 +505,7 @@ OnSharedPreferenceChangeListener
((GeckoApplication) getApplication()).onActivityResume(this);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (Versions.feature11Plus) {
// Watch prefs, otherwise we don't reliably get told when they change.
// See documentation for onSharedPreferenceChange for more.
// Inexplicably only needed on tablet.
@ -1233,7 +1233,7 @@ OnSharedPreferenceChangeListener
public void prefValue(String prefName, final boolean value) {
final Preference pref = getField(prefName);
final CheckBoxPrefSetter prefSetter;
if (Build.VERSION.SDK_INT < 14) {
if (Versions.preICS) {
prefSetter = new CheckBoxPrefSetter();
} else {
prefSetter = new TwoStatePrefSetter();
@ -1283,7 +1283,7 @@ OnSharedPreferenceChangeListener
final Preference pref = getField(prefName);
final CheckBoxPrefSetter prefSetter;
if (PREFS_GEO_REPORTING.equals(prefName)) {
if (Build.VERSION.SDK_INT < 14) {
if (Versions.preICS) {
prefSetter = new CheckBoxPrefSetter();
} else {
prefSetter = new TwoStatePrefSetter();
@ -1338,7 +1338,7 @@ OnSharedPreferenceChangeListener
return;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
if (Versions.preHC) {
intent.putExtra("resource", resource);
} else {
intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName());

View File

@ -10,6 +10,7 @@ import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.R;
import org.mozilla.gecko.gfx.BitmapUtils;
@ -17,7 +18,6 @@ import org.mozilla.gecko.gfx.BitmapUtils;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.os.Build;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
@ -85,7 +85,7 @@ public class IconGridInput extends PromptInput implements OnItemClickListener {
// Despite what the docs say, setItemChecked was not moved into the AbsListView class until sometime between
// Android 2.3.7 and Android 4.0.3. For other versions the item won't be visually highlighted, BUT we really only
// mSelected will still be set so that we default to its behavior.
if (Build.VERSION.SDK_INT >= 11 && mSelected > -1) {
if (Versions.feature11Plus && mSelected > -1) {
view.setItemChecked(mSelected, true);
}

View File

@ -10,13 +10,13 @@ import java.util.Calendar;
import java.util.GregorianCalendar;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.widget.AllCapsTextView;
import org.mozilla.gecko.widget.DateTimePicker;
import org.mozilla.gecko.widget.FloatingHintEditText;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.text.Html;
import android.text.InputType;
import android.text.TextUtils;
@ -229,7 +229,7 @@ public class PromptInput {
@Override
public Object getValue() {
if (Build.VERSION.SDK_INT < 11 && mType.equals("date")) {
if (Versions.preHC && mType.equals("date")) {
// We can't use the custom DateTimePicker with a sdk older than 11.
// Fallback on the native DatePicker.
DatePicker dp = (DatePicker)mView;
@ -278,7 +278,7 @@ public class PromptInput {
}
public View getView(final Context context) throws UnsupportedOperationException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
if (Versions.preHC) {
spinner = new Spinner(context);
} else {
spinner = new Spinner(context, Spinner.MODE_DIALOG);
@ -291,7 +291,8 @@ public class PromptInput {
spinner.setAdapter(adapter);
spinner.setSelection(mSelected);
}
} catch(Exception ex) { }
} catch (Exception ex) {
}
if (!TextUtils.isEmpty(mLabel)) {
LinearLayout container = new LinearLayout(context);

View File

@ -5,30 +5,24 @@
package org.mozilla.gecko.prompts;
import java.util.LinkedHashMap;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
import java.util.LinkedHashMap;
public class TabInput extends PromptInput implements AdapterView.OnItemClickListener {
public static final String INPUT_TYPE = "tabs";
public static final String LOGTAG = "GeckoTabInput";
@ -76,7 +70,7 @@ public class TabInput extends PromptInput implements AdapterView.OnItemClickList
});
// On older android versions, we use a custom style for the tabs.
if (Build.VERSION.SDK_INT < 11) {
if (Versions.preHC) {
TextView textview = (TextView) inflater.inflate(R.layout.tab_prompt_tab, null);
textview.setText(title);
spec.setIndicator(textview);

View File

@ -14,6 +14,7 @@ import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.config.AccountPickler;
import org.mozilla.gecko.sync.config.ClientRecordTerminator;
import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
import org.mozilla.gecko.sync.setup.Constants;
import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
@ -77,6 +78,10 @@ public class SyncAccountDeletedService extends IntentService {
Logger.info(LOG_TAG, "Account named " + accountName + " being removed; " +
"deleting client record from server.");
deleteClientRecord(context, accountName, params.password, params.serverURL);
// Delete client database and non-local tabs.
Logger.info(LOG_TAG, "Deleting the entire clients database and non-local tabs");
FennecTabsRepository.deleteNonLocalClientsAndTabs(context);
}
public static void deletePickle(final Context context) {

View File

@ -33,6 +33,8 @@ import android.net.Uri;
import android.os.RemoteException;
public class FennecTabsRepository extends Repository {
private static final String LOG_TAG = "FennecTabsRepository";
protected final ClientsDataDelegate clientsDataDelegate;
public FennecTabsRepository(ClientsDataDelegate clientsDataDelegate) {
@ -351,4 +353,35 @@ public class FennecTabsRepository extends Repository {
return record;
}
/**
* Deletes all non-local clients and remote tabs.
*
* This function doesn't delete non-local clients due to bug in TabsProvider. Refer Bug 1025128.
*
* Upon remote tabs deletion, the clients without tabs are not shown in UI.
*/
public static void deleteNonLocalClientsAndTabs(Context context) {
final String nonLocalTabsSelection = BrowserContract.Tabs.CLIENT_GUID + " IS NOT NULL";
ContentProviderClient tabsProvider = context.getContentResolver()
.acquireContentProviderClient(BrowserContractHelpers.TABS_CONTENT_URI);
if (tabsProvider == null) {
Logger.warn(LOG_TAG, "Unable to create tabsProvider!");
return;
}
try {
Logger.info(LOG_TAG, "Clearing all non-local tabs for default profile.");
tabsProvider.delete(BrowserContractHelpers.TABS_CONTENT_URI, nonLocalTabsSelection, null);
} catch (RemoteException e) {
Logger.warn(LOG_TAG, "Error while deleting", e);
} finally {
try {
tabsProvider.release();
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception releasing tabsProvider!", e);
}
}
}
}

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko.tabspanel;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoAppShell.AppStateListener;
@ -25,7 +26,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@ -42,7 +42,6 @@ public class TabsPanel extends LinearLayout
implements GeckoPopupMenu.OnMenuItemClickListener,
LightweightTheme.OnChangeListener,
IconTabWidget.OnTabChangedListener {
@SuppressWarnings("unused")
private static final String LOGTAG = "Gecko" + TabsPanel.class.getSimpleName();
public static enum Panel {
@ -508,7 +507,7 @@ public class TabsPanel extends LinearLayout
public void prepareTabsAnimation(PropertyAnimator animator) {
// Not worth doing this on pre-Honeycomb without proper
// hardware accelerated animations.
if (Build.VERSION.SDK_INT < 11) {
if (Versions.preHC) {
return;
}
@ -539,7 +538,7 @@ public class TabsPanel extends LinearLayout
}
public void finishTabsAnimation() {
if (Build.VERSION.SDK_INT < 11) {
if (Versions.preHC) {
return;
}

View File

@ -3,6 +3,24 @@
* 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/. */
const TAG = "AndroidLogTest";
const VERBOSE_MESSAGE = "This is a verbose message.";
const DEBUG_MESSAGE = "This is a debug message.";
const INFO_MESSAGE = "This is an info message.";
const WARNING_MESSAGE = "This is a warning message.";
const ERROR_MESSAGE = "This is an error message.";
// Number of bytes we expect to log. This isn't equivalent to the number
// of characters, although the difference is consistent, so we can calculate it
// from the lengths of the messages and tag. We include the length of "Gecko"
// because the module prepends it to the tag.
const VERBOSE_BYTES = "Gecko".length + TAG.length + VERBOSE_MESSAGE.length + 3;
const DEBUG_BYTES = "Gecko".length + TAG.length + DEBUG_MESSAGE.length + 3;
const INFO_BYTES = "Gecko".length + TAG.length + INFO_MESSAGE.length + 3;
const WARNING_BYTES = "Gecko".length + TAG.length + WARNING_MESSAGE.length + 3;
const ERROR_BYTES = "Gecko".length + TAG.length + ERROR_MESSAGE.length + 3;
add_task(function test_AndroidLog() {
Components.utils.import("resource://gre/modules/AndroidLog.jsm");
@ -14,22 +32,30 @@ add_task(function test_AndroidLog() {
do_check_true("w" in AndroidLog && typeof AndroidLog.w == "function");
do_check_true("e" in AndroidLog && typeof AndroidLog.e == "function");
// I don't know how to check that these messages actually make it to the log,
// but at least we can ensure that they don't cause the test process to crash
// Ensure that the functions don't cause the test process to crash
// (because of some change to the native object being accessed via ctypes)
// and return the right values (the number of bytes--not characters--logged).
do_check_eq(48, AndroidLog.v("AndroidLogTest", "This is a verbose message."));
do_check_eq(46, AndroidLog.d("AndroidLogTest", "This is a debug message."));
do_check_eq(46, AndroidLog.i("AndroidLogTest", "This is an info message."));
do_check_eq(48, AndroidLog.w("AndroidLogTest", "This is a warning message."));
do_check_eq(47, AndroidLog.e("AndroidLogTest", "This is an error message."));
// and return the right values (the number of bytes logged).
// XXX Ensure that these messages actually make it to the log (bug 1046096).
do_check_eq(VERBOSE_BYTES, AndroidLog.v(TAG, VERBOSE_MESSAGE));
do_check_eq(DEBUG_BYTES, AndroidLog.d(TAG, DEBUG_MESSAGE));
do_check_eq(INFO_BYTES, AndroidLog.i(TAG, INFO_MESSAGE));
do_check_eq(WARNING_BYTES, AndroidLog.w(TAG, WARNING_MESSAGE));
do_check_eq(ERROR_BYTES, AndroidLog.e(TAG, ERROR_MESSAGE));
// Ensure the functions work when bound with null value for thisArg parameter.
do_check_eq(48, AndroidLog.v.bind(null, "AndroidLogTest")("This is a verbose message."));
do_check_eq(46, AndroidLog.d.bind(null, "AndroidLogTest")("This is a debug message."));
do_check_eq(46, AndroidLog.i.bind(null, "AndroidLogTest")("This is an info message."));
do_check_eq(48, AndroidLog.w.bind(null, "AndroidLogTest")("This is a warning message."));
do_check_eq(47, AndroidLog.e.bind(null, "AndroidLogTest")("This is an error message."));
do_check_eq(VERBOSE_BYTES, AndroidLog.v.bind(null, TAG)(VERBOSE_MESSAGE));
do_check_eq(DEBUG_BYTES, AndroidLog.d.bind(null, TAG)(DEBUG_MESSAGE));
do_check_eq(INFO_BYTES, AndroidLog.i.bind(null, TAG)(INFO_MESSAGE));
do_check_eq(WARNING_BYTES, AndroidLog.w.bind(null, TAG)(WARNING_MESSAGE));
do_check_eq(ERROR_BYTES, AndroidLog.e.bind(null, TAG)(ERROR_MESSAGE));
// Ensure the functions work when the module object is "bound" to a tag.
let Log = AndroidLog.bind(TAG);
do_check_eq(VERBOSE_BYTES, Log.v(VERBOSE_MESSAGE));
do_check_eq(DEBUG_BYTES, Log.d(DEBUG_MESSAGE));
do_check_eq(INFO_BYTES, Log.i(INFO_MESSAGE));
do_check_eq(WARNING_BYTES, Log.w(WARNING_MESSAGE));
do_check_eq(ERROR_BYTES, Log.e(ERROR_MESSAGE));
// Ensure the functions work when the tag length is greater than the maximum
// tag length.

View File

@ -11,6 +11,7 @@ import java.util.EnumSet;
import java.util.List;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
@ -39,16 +40,12 @@ import org.mozilla.gecko.widget.ThemedRelativeLayout;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MotionEvent;
@ -219,7 +216,7 @@ public class BrowserToolbar extends ThemedRelativeLayout
tabsButton = (ShapedButton) findViewById(R.id.tabs);
tabsCounter = (TabCounter) findViewById(R.id.tabs_counter);
if (Build.VERSION.SDK_INT >= 11) {
if (Versions.feature11Plus) {
tabsCounter.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
@ -1004,7 +1001,7 @@ public class BrowserToolbar extends ThemedRelativeLayout
urlBarEntry.setLayoutParams(urlBarEntryShrunkenLayoutParams);
}
if (Build.VERSION.SDK_INT < 11) {
if (Versions.preHC) {
showEditingOnPreHoneycomb(entryTranslation, curveTranslation);
} else {
showEditingWithPhoneAnimation(animator, entryTranslation, curveTranslation);
@ -1133,7 +1130,7 @@ public class BrowserToolbar extends ThemedRelativeLayout
// not selected so clear the selection by clearing focus.
urlEditLayout.clearFocus();
if (Build.VERSION.SDK_INT < 11) {
if (Versions.preHC) {
stopEditingOnPreHoneycomb();
} else if (HardwareUtils.isTablet()) {
stopEditingOnTablet();

View File

@ -4,6 +4,8 @@
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.AppConstants.Versions;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
@ -11,7 +13,6 @@ import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.os.Build;
class CanvasDelegate {
Paint mPaint;
@ -50,7 +51,7 @@ class CanvasDelegate {
if (path != null && !path.isEmpty()) {
// ICS added double-buffering, which made it easier for drawing the Path directly over the DST.
// In pre-ICS, drawPath() doesn't seem to use ARGB_8888 mode for performance, hence transparency is not preserved.
if (Build.VERSION.SDK_INT >= 14) {
if (Versions.feature14Plus) {
mPaint.setXfermode(mMode);
canvas.drawPath(path, mPaint);
} else {

View File

@ -5,19 +5,18 @@
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.animation.Rotate3DAnimation;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import org.mozilla.gecko.animation.Rotate3DAnimation;
import org.mozilla.gecko.widget.ThemedTextSwitcher;
import android.content.Context;
import android.os.Build;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AlphaAnimation;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.AnimationSet;
import android.widget.ViewSwitcher;
public class TabCounter extends ThemedTextSwitcher
@ -53,7 +52,7 @@ public class TabCounter extends ThemedTextSwitcher
removeAllViews();
setFactory(this);
if (Build.VERSION.SDK_INT >= 16) {
if (Versions.feature16Plus) {
// This adds the TextSwitcher to the a11y node tree, where we in turn
// could make it return an empty info node. If we don't do this the
// TextSwitcher's child TextViews get picked up, and we don't want

View File

@ -5,47 +5,41 @@
package org.mozilla.gecko.toolbar;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.R;
import org.mozilla.gecko.SiteIdentity;
import org.mozilla.gecko.SiteIdentity.SecurityMode;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.toolbar.BrowserToolbar.ForwardButtonAnimation;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.widget.ThemedLinearLayout;
import org.mozilla.gecko.widget.ThemedTextView;
import org.json.JSONObject;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.SystemClock;
import android.text.style.ForegroundColorSpan;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout.LayoutParams;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
/**
* {@code ToolbarDisplayLayout} is the UI for when the toolbar is in
@ -152,7 +146,7 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout
mPrivateDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext_private));
mFavicon = (ImageButton) findViewById(R.id.favicon);
if (Build.VERSION.SDK_INT >= 16) {
if (Versions.feature16Plus) {
mFavicon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
mFaviconSize = Math.round(res.getDimension(R.dimen.browser_toolbar_favicon_size));

View File

@ -5,19 +5,17 @@
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.R;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.CustomEditText;
import org.mozilla.gecko.InputMethods;
import org.mozilla.gecko.toolbar.BrowserToolbar.OnCommitListener;
import org.mozilla.gecko.toolbar.BrowserToolbar.OnDismissListener;
import org.mozilla.gecko.toolbar.BrowserToolbar.OnFilterListener;
import org.mozilla.gecko.CustomEditText;
import org.mozilla.gecko.CustomEditText.OnKeyPreImeListener;
import org.mozilla.gecko.InputMethods;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.StringUtils;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.text.Editable;
import android.text.NoCopySpan;
import android.text.Selection;
@ -29,7 +27,6 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@ -547,8 +544,8 @@ public class ToolbarEditText extends CustomEditText
}
if ((keyCode == KeyEvent.KEYCODE_DEL ||
(Build.VERSION.SDK_INT >= 11 &&
keyCode == KeyEvent.KEYCODE_FORWARD_DEL)) &&
(Versions.feature11Plus &&
keyCode == KeyEvent.KEYCODE_FORWARD_DEL)) &&
removeAutocomplete(getText())) {
// Delete autocomplete text when backspacing or forward deleting.
return true;

View File

@ -16,17 +16,18 @@
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.AppConstants.Versions;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.view.View;
import android.view.animation.Animation;
import android.widget.ImageView;
/**
* Progress view used for page loads.
@ -42,8 +43,6 @@ public class ToolbarProgressView extends ImageView {
private static final int STEPS = 10;
private static final int DELAY = 40;
private static final boolean PRE_HONEYCOMB = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
private int mTargetProgress;
private int mIncrement;
private Rect mBounds;
@ -99,7 +98,7 @@ public class ToolbarProgressView extends ImageView {
public void setVisibility(int visibility) {
// On GB/Froyo, setting the visibility to GONE/HIDDEN alone does not
// work with translations. Calling clearAnimation acts as a workaround.
if (PRE_HONEYCOMB && visibility != VISIBLE) {
if (Versions.preHC && visibility != VISIBLE) {
clearAnimation();
}
@ -111,7 +110,7 @@ public class ToolbarProgressView extends ImageView {
// On GB/Froyo, setting the animation after hiding the view causes it
// to reappear. As a workaround, disallow setAnimation from being
// called if the view is not shown.
if (PRE_HONEYCOMB && isShown()) {
if (Versions.preHC && isShown()) {
super.setAnimation(animation);
}
}

View File

@ -14,6 +14,7 @@ import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.ActivityHandlerHelper;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoProfile;
@ -31,8 +32,6 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
public class EventListener implements NativeEventListener {
@ -204,11 +203,11 @@ public class EventListener implements NativeEventListener {
}
public static void uninstallApk(final Activity context, NativeJSObject message) {
String packageName = message.getString("apkPackageName");
Uri packageUri = Uri.parse("package:" + packageName);
final String packageName = message.getString("apkPackageName");
final Uri packageUri = Uri.parse("package:" + packageName);
Intent intent;
if (Build.VERSION.SDK_INT < 14) {
final Intent intent;
if (Versions.preICS) {
intent = new Intent(Intent.ACTION_DELETE, packageUri);
} else {
intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko.widget;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import org.mozilla.gecko.util.HardwareUtils;
@ -12,7 +13,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -127,9 +127,9 @@ public abstract class ArrowPopup extends PopupWindow {
if (mAnchor == null || anchorLocation[1] < 0) {
final View decorView = ((Activity) mContext).getWindow().getDecorView();
// Bug in android code causes the window layout parameters to be ignored
// Bug in Android code causes the window layout parameters to be ignored
// when using showAtLocation() in Gingerbread phones.
if (Build.VERSION.SDK_INT < 11) {
if (Versions.preHC) {
setWidth(decorView.getWidth());
setHeight(decorView.getHeight());
}

View File

@ -16,10 +16,15 @@
package org.mozilla.gecko.widget;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.R;
import android.content.Context;
import android.os.Build;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.DisplayMetrics;
@ -35,16 +40,9 @@ import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.NumberPicker;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
public class DateTimePicker extends FrameLayout {
private static final boolean DEBUG = true;
private static final String LOGTAG = "GeckoDateTimePicker";
private static final String DATE_FORMAT = "MM/dd/yyyy";
private static final int DEFAULT_START_YEAR = 1;
private static final int DEFAULT_END_YEAR = 9999;
// Minimal screen width (in inches) for which we can show the calendar;
@ -97,11 +95,14 @@ public class DateTimePicker extends FrameLayout {
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
updateInputState();
mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
boolean newBehavior = (Build.VERSION.SDK_INT > 10);
final boolean newBehavior = Versions.feature11Plus;
if (newBehavior) {
if (DEBUG) Log.d(LOGTAG, "Sdk version > 10, using new behavior");
//The native date picker widget on these sdks increment
//the next field when one field reach the maximum
if (DEBUG) {
Log.d(LOGTAG, "SDK version > 10, using new behavior");
}
// The native date picker widget on these SDKs increments
// the next field when one field reaches the maximum.
if (picker == mDaySpinner && mDayEnabled) {
int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
int old = mTempDate.get(Calendar.DAY_OF_MONTH);
@ -118,7 +119,7 @@ public class DateTimePicker extends FrameLayout {
mTempDate.set(Calendar.YEAR,newVal);
// Changing the year shouldn't change the month. (in case of non-leap year a Feb 29)
// change the day instead;
if (month != mTempDate.get(Calendar.MONTH)){
if (month != mTempDate.get(Calendar.MONTH)) {
mTempDate.set(Calendar.MONTH, month);
mTempDate.set(Calendar.DAY_OF_MONTH,
mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH));
@ -184,7 +185,7 @@ public class DateTimePicker extends FrameLayout {
}
private void setTempDate(int field, int oldVal, int newVal, int min, int max) {
if (oldVal == max && newVal == min ) {
if (oldVal == max && newVal == min) {
mTempDate.add(field, 1);
} else if (oldVal == min && newVal == max) {
mTempDate.add(field, -1);
@ -216,6 +217,7 @@ public class DateTimePicker extends FrameLayout {
if (mState == PickersState.DATETIME) {
return;
}
setHourShown(false);
setMinuteShown(false);
if (mState == PickersState.WEEK) {
@ -233,9 +235,10 @@ public class DateTimePicker extends FrameLayout {
public DateTimePicker(Context context, String dateFormat, String dateTimeValue, PickersState state) {
super(context);
if (Build.VERSION.SDK_INT < 11) {
if (Versions.preHC) {
throw new UnsupportedOperationException("Custom DateTimePicker is only available for SDK > 10");
}
setCurrentLocale(Locale.getDefault());
mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
@ -257,13 +260,22 @@ public class DateTimePicker extends FrameLayout {
display.getMetrics(dm);
mScreenWidth = display.getWidth() / dm.densityDpi;
mScreenHeight = display.getHeight() / dm.densityDpi;
if (DEBUG) Log.d(LOGTAG, "screen width: " + mScreenWidth + " screen height: " + mScreenHeight);
// If we're displaying a date, the screen is wide enought (and if we're using a sdk where the calendar view exists)
if (DEBUG) {
Log.d(LOGTAG, "screen width: " + mScreenWidth + " screen height: " + mScreenHeight);
}
// If we're displaying a date, the screen is wide enough
// (and if we're using an SDK where the calendar view exists)
// then display a calendar.
if ((mState == PickersState.DATE || mState == PickersState.DATETIME) &&
Build.VERSION.SDK_INT > 10 && mScreenWidth >= SCREEN_SIZE_THRESHOLD) {
if (DEBUG) Log.d(LOGTAG,"SDK > 10 and screen wide enough, displaying calendar");
if (Versions.feature11Plus &&
(mState == PickersState.DATE || mState == PickersState.DATETIME) &&
mScreenWidth >= SCREEN_SIZE_THRESHOLD) {
if (DEBUG) {
Log.d(LOGTAG,"SDK > 10 and screen wide enough, displaying calendar");
}
mCalendar = new CalendarView(context);
mCalendar.setVisibility(GONE);
@ -286,9 +298,9 @@ public class DateTimePicker extends FrameLayout {
mPickers.addView(mCalendar);
} else {
// If the screen is more wide than high, we are displaying daye and time spinners,
// and if there is no calendar displayed,
// we should display the fields in one row.
// If the screen is more wide than high, we are displaying day and
// time spinners, and if there is no calendar displayed, we should
// display the fields in one row.
if (mScreenWidth > mScreenHeight && mState == PickersState.DATETIME) {
mSpinners.setOrientation(LinearLayout.HORIZONTAL);
}
@ -349,11 +361,13 @@ public class DateTimePicker extends FrameLayout {
// The order in which the spinners are displayed are locale-dependent
reorderDateSpinners();
// Set the date to the initial date. Since this date can come from the user,
// it can fire an exception (out-of-bound date)
try {
updateDate(mTempDate);
} catch (Exception ex) { }
} catch (Exception ex) {
}
// Display only the pickers needed for the current state.
displayPickers();
@ -495,13 +509,17 @@ public class DateTimePicker extends FrameLayout {
}
public void toggleCalendar(boolean shown) {
if ((mState != PickersState.DATE && mState != PickersState.DATETIME) ||
Build.VERSION.SDK_INT < 11 || mScreenWidth < SCREEN_SIZE_THRESHOLD) {
if (DEBUG) Log.d(LOGTAG,"Cannot display calendar on this device, in this state" +
": screen width :"+mScreenWidth);
if (Versions.preHC ||
(mState != PickersState.DATE && mState != PickersState.DATETIME) ||
mScreenWidth < SCREEN_SIZE_THRESHOLD) {
if (DEBUG) {
Log.d(LOGTAG, "Cannot display calendar on this device, in this state" +
": screen width :" + mScreenWidth);
}
return;
}
if (shown){
if (shown) {
mCalendarEnabled = true;
mCalendar.setVisibility(VISIBLE);
setYearShown(false);
@ -622,12 +640,12 @@ public class DateTimePicker extends FrameLayout {
private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
if (oldCalendar == null) {
return Calendar.getInstance(locale);
} else {
final long currentTimeMillis = oldCalendar.getTimeInMillis();
Calendar newCalendar = Calendar.getInstance(locale);
newCalendar.setTimeInMillis(currentTimeMillis);
return newCalendar;
}
final long currentTimeMillis = oldCalendar.getTimeInMillis();
Calendar newCalendar = Calendar.getInstance(locale);
newCalendar.setTimeInMillis(currentTimeMillis);
return newCalendar;
}
public void updateDate(Calendar calendar) {
@ -643,6 +661,4 @@ public class DateTimePicker extends FrameLayout {
updateSpinners();
notifyDateChanged();
}
}

View File

@ -16,6 +16,8 @@
package org.mozilla.gecko.widget;
import org.mozilla.gecko.AppConstants.Versions;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@ -350,7 +352,7 @@ public class GeckoSwipeRefreshLayout extends ViewGroup {
* scroll up. Override this if the child view is a custom view.
*/
public boolean canChildScrollUp() {
if (android.os.Build.VERSION.SDK_INT < 14) {
if (Versions.preICS) {
if (mTarget instanceof AbsListView) {
final AbsListView absListView = (AbsListView) mTarget;
return absListView.getChildCount() > 0

View File

@ -5,21 +5,19 @@
package org.mozilla.gecko.widget;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.animation.ViewHelper;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ViewFlipper;
import android.util.Log;
import android.util.AttributeSet;
/* This extends the normal ViewFlipper only to fix bug 956075 on < 3.0 devices.
* i.e. It ignores touch events on the ViewFlipper when its hidden. */
public class GeckoViewFlipper extends ViewFlipper {
private static final String LOGTAG = "GeckoViewFlipper";
private Rect mRect = new Rect();
public GeckoViewFlipper(Context context) {
@ -32,7 +30,7 @@ public class GeckoViewFlipper extends ViewFlipper {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (Build.VERSION.SDK_INT < 11) {
if (Versions.preHC) {
// Fix bug 956075. Don't allow touching this View if its hidden.
getHitRect(mRect);
mRect.offset((int) ViewHelper.getTranslationX(this), (int) ViewHelper.getTranslationY(this));

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -4,6 +4,9 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Define elements that bound phone number containers.
const PHONE_NUMBER_CONTAINERS = "td,div";
var SelectionHandler = {
HANDLE_TYPE_START: "START",
HANDLE_TYPE_MIDDLE: "MIDDLE",
@ -317,42 +320,6 @@ var SelectionHandler = {
return false;
}
if (this._isPhoneNumber(selection.toString())) {
let anchorNode = selection.anchorNode;
let anchorOffset = selection.anchorOffset;
let focusNode = null;
let focusOffset = null;
while (this._isPhoneNumber(selection.toString().trim())) {
focusNode = selection.focusNode;
focusOffset = selection.focusOffset;
selection.modify("extend", "forward", "word");
// if we hit the end of the text on the page, we can't advance the selection
if (focusNode == selection.focusNode && focusOffset == selection.focusOffset) {
break;
}
}
// reverse selection
selection.collapse(focusNode, focusOffset);
selection.extend(anchorNode, anchorOffset);
anchorNode = focusNode;
anchorOffset = focusOffset
while (this._isPhoneNumber(selection.toString().trim())) {
focusNode = selection.focusNode;
focusOffset = selection.focusOffset;
selection.modify("extend", "backward", "word");
// if we hit the end of the text on the page, we can't advance the selection
if (focusNode == selection.focusNode && focusOffset == selection.focusOffset) {
break;
}
}
selection.collapse(focusNode, focusOffset);
selection.extend(anchorNode, anchorOffset);
}
// Add a listener to end the selection if it's removed programatically
selection.QueryInterface(Ci.nsISelectionPrivate).addSelectionListener(this);
this._activeType = this.TYPE_SELECTION;
@ -389,7 +356,16 @@ var SelectionHandler = {
if (aOptions.mode == this.SELECT_AT_POINT) {
// Clear any ranges selected outside SelectionHandler, by code such as Find-In-Page.
this._contentWindow.getSelection().removeAllRanges();
return this._domWinUtils.selectAtPoint(aOptions.x, aOptions.y, Ci.nsIDOMWindowUtils.SELECT_WORDNOSPACE);
if (!this._domWinUtils.selectAtPoint(aOptions.x, aOptions.y, Ci.nsIDOMWindowUtils.SELECT_WORDNOSPACE)) {
return false;
}
// Perform additional phone-number "smart selection".
if (this._isPhoneNumber(this._getSelection().toString())) {
this._selectSmartPhoneNumber();
}
return true;
}
if (aOptions.mode != this.SELECT_ALL) {
@ -429,6 +405,71 @@ var SelectionHandler = {
return true;
},
/*
* Called to expand a selection that appears to represent a phone number. This enhances the basic
* SELECT_WORDNOSPACE logic employed in performSelection() in response to long-tap / selecting text.
*/
_selectSmartPhoneNumber: function() {
this._extendPhoneNumberSelection("forward");
this._reversePhoneNumberSelectionDir();
this._extendPhoneNumberSelection("backward");
this._reversePhoneNumberSelectionDir();
},
/*
* Extend the current phone number selection in the requested direction.
*/
_extendPhoneNumberSelection: function(direction) {
let selection = this._getSelection();
// Extend the phone number selection until we find a boundry.
while (true) {
// Save current focus position, and extend the selection.
let focusNode = selection.focusNode;
let focusOffset = selection.focusOffset;
selection.modify("extend", direction, "character");
// If the selection doesn't change, (can't extend further), we're done.
if (selection.focusNode == focusNode && selection.focusOffset == focusOffset) {
return;
}
// Don't extend past a valid phone number.
if (!this._isPhoneNumber(selection.toString().trim())) {
// Backout the undesired selection extend, and we're done.
selection.collapse(selection.anchorNode, selection.anchorOffset);
selection.extend(focusNode, focusOffset);
return;
}
// Don't extend the selection into a new container.
if (selection.focusNode != focusNode) {
let nextContainer = (selection.focusNode instanceof Text) ?
selection.focusNode.parentNode : selection.focusNode;
if (nextContainer.mozMatchesSelector &&
nextContainer.mozMatchesSelector(PHONE_NUMBER_CONTAINERS)) {
// Backout the undesired selection extend, and we're done.
selection.collapse(selection.anchorNode, selection.anchorOffset);
selection.extend(focusNode, focusOffset);
return
}
}
}
},
/*
* Reverse the the selection direction, swapping anchorNode <-+-> focusNode.
*/
_reversePhoneNumberSelectionDir: function(direction) {
let selection = this._getSelection();
let anchorNode = selection.anchorNode;
let anchorOffset = selection.anchorOffset;
selection.collapse(selection.focusNode, selection.focusOffset);
selection.extend(anchorNode, anchorOffset);
},
/* Return true if the current selection (given by aPositions) is near to where the coordinates passed in */
_selectionNearClick: function(aX, aY, aPositions) {
let distance = 0;

View File

@ -380,6 +380,7 @@
@BINPATH@/components/nsInputListAutoComplete.js
@BINPATH@/components/formautofill.manifest
@BINPATH@/components/FormAutofillContentService.js
@BINPATH@/components/FormAutofillStartup.js
@BINPATH@/components/contentSecurityPolicy.manifest
@BINPATH@/components/contentSecurityPolicy.js
@BINPATH@/components/contentAreaDropListener.manifest

View File

@ -27,6 +27,12 @@
* // Bind a function with a tag to replace a bespoke dump/log/debug function:
* let debug = Log.d.bind(null, "MyModule");
* debug("This is a debug message.");
* // Outputs "D/GeckoMyModule(#####): This is a debug message."
*
* // Or "bind" the module object to a tag to automatically tag messages:
* Log = Log.bind("MyModule");
* Log.d("This is a debug message.");
* // Outputs "D/GeckoMyModule(#####): This is a debug message."
*
* Note: the module automatically prepends "Gecko" to the tag you specify,
* since all tags used by Fennec code should start with that string; and it
@ -67,6 +73,17 @@ let AndroidLog = {
i: (tag, msg) => __android_log_write(ANDROID_LOG_INFO, "Gecko" + tag.substring(0, MAX_TAG_LENGTH), msg),
w: (tag, msg) => __android_log_write(ANDROID_LOG_WARN, "Gecko" + tag.substring(0, MAX_TAG_LENGTH), msg),
e: (tag, msg) => __android_log_write(ANDROID_LOG_ERROR, "Gecko" + tag.substring(0, MAX_TAG_LENGTH), msg),
bind: function(tag) {
return {
MAX_TAG_LENGTH: MAX_TAG_LENGTH,
v: AndroidLog.v.bind(null, tag),
d: AndroidLog.d.bind(null, tag),
i: AndroidLog.i.bind(null, tag),
w: AndroidLog.w.bind(null, tag),
e: AndroidLog.e.bind(null, tag),
};
},
};
if (typeof Components == "undefined") {

View File

@ -260,11 +260,13 @@ nsAutoCompleteController::HandleEnter(bool aIsPopupSelection, bool *_retval)
if (!mInput)
return NS_OK;
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
// allow the event through unless there is something selected in the popup
mInput->GetPopupOpen(_retval);
input->GetPopupOpen(_retval);
if (*_retval) {
nsCOMPtr<nsIAutoCompletePopup> popup;
mInput->GetPopup(getter_AddRefs(popup));
input->GetPopup(getter_AddRefs(popup));
if (popup) {
int32_t selectedIndex;
@ -287,8 +289,10 @@ nsAutoCompleteController::HandleEscape(bool *_retval)
if (!mInput)
return NS_OK;
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
// allow the event through if the popup is closed
mInput->GetPopupOpen(_retval);
input->GetPopupOpen(_retval);
// Stop all searches in case they are async.
StopSearch();
@ -986,16 +990,18 @@ nsAutoCompleteController::ClosePopup()
return NS_OK;
}
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
bool isOpen = false;
mInput->GetPopupOpen(&isOpen);
input->GetPopupOpen(&isOpen);
if (!isOpen)
return NS_OK;
nsCOMPtr<nsIAutoCompletePopup> popup;
mInput->GetPopup(getter_AddRefs(popup));
input->GetPopup(getter_AddRefs(popup));
NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
popup->SetSelectedIndex(-1);
return mInput->SetPopupOpen(false);
return input->SetPopupOpen(false);
}
nsresult
@ -1114,9 +1120,11 @@ nsAutoCompleteController::StartSearches()
if (mTimer || !mInput)
return NS_OK;
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
// Get the timeout for delayed searches.
uint32_t timeout;
mInput->GetTimeout(&timeout);
input->GetTimeout(&timeout);
uint32_t immediateSearchesCount = mImmediateSearchesCount;
if (timeout == 0) {
@ -1442,10 +1450,12 @@ nsAutoCompleteController::CompleteDefaultIndex(int32_t aResultIndex)
if (mDefaultIndexCompleted || mBackspaced || mSearchString.Length() == 0 || !mInput)
return NS_OK;
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
int32_t selectionStart;
mInput->GetSelectionStart(&selectionStart);
input->GetSelectionStart(&selectionStart);
int32_t selectionEnd;
mInput->GetSelectionEnd(&selectionEnd);
input->GetSelectionEnd(&selectionEnd);
// Don't try to automatically complete to the first result if there's already
// a selection or the cursor isn't at the end of the input
@ -1454,7 +1464,7 @@ nsAutoCompleteController::CompleteDefaultIndex(int32_t aResultIndex)
return NS_OK;
bool shouldComplete;
mInput->GetCompleteDefaultIndex(&shouldComplete);
input->GetCompleteDefaultIndex(&shouldComplete);
if (!shouldComplete)
return NS_OK;
@ -1554,6 +1564,7 @@ nsresult
nsAutoCompleteController::GetFinalDefaultCompleteValue(nsAString &_retval)
{
MOZ_ASSERT(mInput, "Must have a valid input");
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
nsIAutoCompleteResult *result;
int32_t defaultIndex = -1;
nsresult rv = GetDefaultCompleteResult(-1, &result, &defaultIndex);
@ -1561,7 +1572,7 @@ nsAutoCompleteController::GetFinalDefaultCompleteValue(nsAString &_retval)
result->GetValueAt(defaultIndex, _retval);
nsAutoString inputValue;
mInput->GetTextValue(inputValue);
input->GetTextValue(inputValue);
if (!_retval.Equals(inputValue, nsCaseInsensitiveStringComparator())) {
return NS_ERROR_FAILURE;
}
@ -1584,6 +1595,7 @@ nsAutoCompleteController::CompleteValue(nsString &aValue)
* contained in mSearchString. */
{
MOZ_ASSERT(mInput, "Must have a valid input");
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
const int32_t mSearchStringLength = mSearchString.Length();
int32_t endSelect = aValue.Length(); // By default, select all of aValue.
@ -1593,7 +1605,7 @@ nsAutoCompleteController::CompleteValue(nsString &aValue)
// aValue is empty (we were asked to clear mInput), or mSearchString
// matches the beginning of aValue. In either case we can simply
// autocomplete to aValue.
mInput->SetTextValue(aValue);
input->SetTextValue(aValue);
} else {
nsresult rv;
nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
@ -1613,22 +1625,22 @@ nsAutoCompleteController::CompleteValue(nsString &aValue)
return NS_OK;
}
mInput->SetTextValue(mSearchString +
Substring(aValue, mSearchStringLength + findIndex,
endSelect));
input->SetTextValue(mSearchString +
Substring(aValue, mSearchStringLength + findIndex,
endSelect));
endSelect -= findIndex; // We're skipping this many characters of aValue.
} else {
// Autocompleting something other than a URI from the middle.
// Use the format "searchstring >> full string" to indicate to the user
// what we are going to replace their search string with.
mInput->SetTextValue(mSearchString + NS_LITERAL_STRING(" >> ") + aValue);
input->SetTextValue(mSearchString + NS_LITERAL_STRING(" >> ") + aValue);
endSelect = mSearchString.Length() + 4 + aValue.Length();
}
}
mInput->SelectTextRange(mSearchStringLength, endSelect);
input->SelectTextRange(mSearchStringLength, endSelect);
return NS_OK;
}

View File

@ -112,4 +112,18 @@ this.FormAutofill = {
this.integration = combined;
},
/**
* Processes a requestAutocomplete message asynchronously.
*
* @param aData
* Provided to FormAutofillIntegration.createRequestAutocompleteUI.
*
* @return {Promise}
* @resolves Structured data received from the requestAutocomplete UI.
*/
processRequestAutocomplete: Task.async(function* (aData) {
let ui = yield FormAutofill.integration.createRequestAutocompleteUI(aData);
return yield ui.show();
}),
};

View File

@ -95,8 +95,37 @@ FormHandler.prototype = {
return "disabled";
}
let ui = yield FormAutofill.integration.createRequestAutocompleteUI(data);
let result = yield ui.show();
// Access the frame message manager of the window starting the request.
let rootDocShell = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.sameTypeRootTreeItem
.QueryInterface(Ci.nsIDocShell);
let frameMM = rootDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
// We need to set up a temporary message listener for our result before we
// send the request to the parent process. At present, there is no check
// for reentrancy (bug 1020459), thus it is possible that we'll receive a
// message for a different request, but this will not be normally allowed.
let promiseRequestAutocompleteResult = new Promise((resolve, reject) => {
frameMM.addMessageListener("FormAutofill:RequestAutocompleteResult",
function onResult(aMessage) {
frameMM.removeMessageListener(
"FormAutofill:RequestAutocompleteResult", onResult);
// Exceptions in the parent process are serialized and propagated in
// the response message that we received.
if ("exception" in aMessage.data) {
reject(aMessage.data.exception);
} else {
resolve(aMessage.data);
}
});
});
// Send the message to the parent process, and wait for the result. This
// will throw an exception if one occurred in the parent process.
frameMM.sendAsyncMessage("FormAutofill:RequestAutocomplete", data);
let result = yield promiseRequestAutocompleteResult;
if (result.canceled) {
return "cancel";
}

View File

@ -0,0 +1,64 @@
/* 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/. */
/*
* Handles startup in the parent process.
*/
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofill",
"resource://gre/modules/FormAutofill.jsm");
/**
* Handles startup in the parent process.
*/
function FormAutofillStartup() {
}
FormAutofillStartup.prototype = {
classID: Components.ID("{51c95b3d-7431-467b-8d50-383f158ce9e5}"),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIFrameMessageListener,
Ci.nsIObserver,
Ci.nsISupportsWeakReference,
]),
// nsIObserver
observe: function (aSubject, aTopic, aData) {
// This method is called by the "profile-after-change" category on startup,
// which is called before any web page loads. At this time, we need to
// register a global message listener in the parent process preemptively,
// because we can receive requests from child processes at any time. For
// performance reasons, we use this object as a message listener, so that we
// don't have to load the FormAutoFill module at startup.
let globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
.getService(Ci.nsIMessageListenerManager);
globalMM.addMessageListener("FormAutofill:RequestAutocomplete", this);
},
// nsIFrameMessageListener
receiveMessage: function (aMessage) {
// Process the "FormAutofill:RequestAutocomplete" message. Any exception
// raised in the parent process is caught and serialized into the reply
// message that is sent to the requesting child process.
FormAutofill.processRequestAutocomplete(aMessage.data)
.catch(ex => { exception: ex })
.then(result => {
// The browser message manager in the parent will send the reply to the
// associated frame message manager in the child.
let browserMM = aMessage.target.messageManager;
browserMM.sendAsyncMessage("FormAutofill:RequestAutocompleteResult",
result);
})
.catch(Cu.reportError);
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FormAutofillStartup]);

View File

@ -1,2 +1,7 @@
component {ed9c2c3c-3f86-4ae5-8e31-10f71b0f19e6} FormAutofillContentService.js
contract @mozilla.org/formautofill/content-service;1 {ed9c2c3c-3f86-4ae5-8e31-10f71b0f19e6}
component {51c95b3d-7431-467b-8d50-383f158ce9e5} FormAutofillStartup.js
contract @mozilla.org/formautofill/startup;1 {51c95b3d-7431-467b-8d50-383f158ce9e5}
#ifdef NIGHTLY_BUILD
category profile-after-change FormAutofillStartup @mozilla.org/formautofill/startup;1
#endif

View File

@ -4,13 +4,14 @@
# 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/.
BROWSER_CHROME_MANIFESTS += [
'test/browser/browser.ini',
]
if CONFIG['NIGHTLY_BUILD']:
BROWSER_CHROME_MANIFESTS += [
'test/browser/browser.ini',
]
MOCHITEST_CHROME_MANIFESTS += [
'test/chrome/chrome.ini',
]
MOCHITEST_CHROME_MANIFESTS += [
'test/chrome/chrome.ini',
]
XPCSHELL_TESTS_MANIFESTS += [
'test/xpcshell/xpcshell.ini',
@ -23,8 +24,12 @@ XPIDL_SOURCES += [
XPIDL_MODULE = 'toolkit_formautofill'
EXTRA_COMPONENTS += [
'formautofill.manifest',
'FormAutofillContentService.js',
'FormAutofillStartup.js',
]
EXTRA_PP_COMPONENTS += [
'formautofill.manifest',
]
EXTRA_JS_MODULES += [

View File

@ -13,3 +13,11 @@
// xpcshell specific test initialization here. If you need shared functions or
// initialization that are not specific to xpcshell, consider adding them to
// "head_common.js" in the parent folder instead.
add_task_in_parent_process(function* test_xpcshell_initialize_profile() {
// We need to send the profile-after-change notification manually to the
// startup component to ensure it has been initialized.
Cc["@mozilla.org/formautofill/startup;1"]
.getService(Ci.nsIObserver)
.observe(null, "profile-after-change", "");
});

View File

@ -134,17 +134,20 @@ function* check_autocomplete(test) {
// Check to see the expected uris and titles match up (in any order)
if (test.matches) {
// Do not modify the test original matches.
let matches = test.matches.slice();
for (let i = 0; i < controller.matchCount; i++) {
let value = controller.getValueAt(i);
let comment = controller.getCommentAt(i);
do_log_info("Looking for '" + value + "', '" + comment + "' in expected results...");
let j;
for (j = 0; j < test.matches.length; j++) {
for (j = 0; j < matches.length; j++) {
// Skip processed expected results
if (test.matches[j] == undefined)
if (matches[j] == undefined)
continue;
let { uri, title, tags } = test.matches[j];
let { uri, title, tags } = matches[j];
if (tags)
title += " \u2013 " + tags.sort().join(", ");
@ -153,7 +156,7 @@ function* check_autocomplete(test) {
if (stripPrefix(uri.spec) == stripPrefix(value) && title == comment) {
do_log_info("Got a match at index " + j + "!");
// Make it undefined so we don't process it again
test.matches[j] = undefined;
matches[j] = undefined;
if (uri.spec.startsWith("moz-action:")) {
let style = controller.getStyleAt(i);
Assert.ok(style.contains("action"));
@ -163,15 +166,15 @@ function* check_autocomplete(test) {
}
// We didn't hit the break, so we must have not found it
if (j == test.matches.length)
if (j == matches.length)
do_throw("Didn't find the current result ('" + value + "', '" + comment + "') in matches");
}
Assert.equal(controller.matchCount, test.matches.length,
Assert.equal(controller.matchCount, matches.length,
"Got as many results as expected");
// If we expect results, make sure we got matches.
do_check_eq(controller.searchStatus, test.matches.length ?
do_check_eq(controller.searchStatus, matches.length ?
Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH :
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH);
}

View File

@ -38,6 +38,7 @@ add_task(function* test_swap_protocol() {
{ uri: uri6, title: "title" }
];
// Disable autoFill to avoid handling the first result.
Services.prefs.setBoolPref("browser.urlbar.autoFill", "false");
do_log_info("http://www.site matches all site");
@ -45,7 +46,7 @@ add_task(function* test_swap_protocol() {
search: "http://www.site",
matches: allMatches
});
/*
do_log_info("http://site matches all site");
yield check_autocomplete({
search: "http://site",
@ -55,7 +56,7 @@ add_task(function* test_swap_protocol() {
do_log_info("ftp://ftp.site matches itself");
yield check_autocomplete({
search: "ftp://ftp.site",
matches: { uri: uri3, title: "title"}
matches: [ { uri: uri3, title: "title" } ]
});
do_log_info("ftp://site matches all site");
@ -144,6 +145,6 @@ add_task(function* test_swap_protocol() {
search: "http://www.www",
matches: [ { uri: uri8, title: "title" } ]
});
*/
yield cleanup();
});

File diff suppressed because one or more lines are too long

View File

@ -19,7 +19,14 @@ Object.defineProperty(this, "QRErrorCorrectLevel", {
get: () => require("./encoder/index").QRErrorCorrectLevel
});
Object.defineProperty(this, "decoder", {
get: () => require("./decoder/index")
get: () => {
// Some applications don't ship the decoder, see moz.build
try {
return require("./decoder/index");
} catch(e) {
return null;
}
}
});
/**
@ -86,6 +93,9 @@ exports.encodeToDataURI = function(message, quality, version) {
* the QR code.
*/
exports.decodeFromURI = function(URI) {
if (!decoder) {
return promise.reject();
}
let deferred = promise.defer();
decoder.decodeFromURI(URI, deferred.resolve, deferred.reject);
return deferred.promise;
@ -99,5 +109,8 @@ exports.decodeFromURI = function(URI) {
* The data inside the QR code
*/
exports.decodeFromCanvas = function(canvas) {
if (!decoder) {
throw new Error("Decoder not available");
}
return decoder.decodeFromCanvas(canvas);
};

View File

@ -5,10 +5,15 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'decoder',
'encoder'
]
# Save file size on Fennec until there are active plans to use the decoder there
if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
DIRS += [
'decoder'
]
JS_MODULES_PATH = 'modules/devtools/qrcode'
EXTRA_JS_MODULES += [

View File

@ -294,11 +294,6 @@ nsUXThemeData::UpdateNativeThemeInfo()
sIsDefaultWindowsTheme = false;
sThemeId = LookAndFeel::eWindowsTheme_Generic;
if (!IsAppThemed()) {
sThemeId = LookAndFeel::eWindowsTheme_Classic;
return;
}
HIGHCONTRAST highContrastInfo;
highContrastInfo.cbSize = sizeof(HIGHCONTRAST);
if (SystemParametersInfo(SPI_GETHIGHCONTRAST, 0, &highContrastInfo, 0)) {
@ -307,6 +302,11 @@ nsUXThemeData::UpdateNativeThemeInfo()
sIsHighContrastOn = false;
}
if (!IsAppThemed()) {
sThemeId = LookAndFeel::eWindowsTheme_Classic;
return;
}
WCHAR themeFileName[MAX_PATH + 1];
WCHAR themeColor[MAX_PATH + 1];
if (FAILED(GetCurrentThemeName(themeFileName,