--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -21,16 +21,20 @@ import org.mozilla.gecko.AppConstants.Ve
import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
import org.mozilla.gecko.Tabs.TabEvents;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.cleanup.FileCleanupController;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.SuggestedSites;
+import org.mozilla.gecko.deeplink.DeepLinkAction;
+import org.mozilla.gecko.deeplink.DeepLinkListener;
+import org.mozilla.gecko.deeplink.DeepLinkStore;
+import org.mozilla.gecko.deeplink.DeepLinkUtil;
import org.mozilla.gecko.delegates.BrowserAppDelegate;
import org.mozilla.gecko.delegates.OfflineTabStatusDelegate;
import org.mozilla.gecko.delegates.ScreenshotDelegate;
import org.mozilla.gecko.distribution.Distribution;
import org.mozilla.gecko.distribution.DistributionStoreCallback;
import org.mozilla.gecko.dlc.DownloadContentService;
import org.mozilla.gecko.icons.IconsHelper;
import org.mozilla.gecko.icons.decoders.IconDirectoryEntry;
@@ -155,18 +159,20 @@ import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ViewFlipper;
+
import org.mozilla.gecko.switchboard.AsyncConfigLoader;
import org.mozilla.gecko.switchboard.SwitchBoard;
+
import android.animation.Animator;
import android.animation.ObjectAnimator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
@@ -175,27 +181,28 @@ import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
import java.util.regex.Pattern;
public class BrowserApp extends GeckoApp
- implements TabsPanel.TabsLayoutChangeListener,
- PropertyAnimator.PropertyAnimationListener,
- View.OnKeyListener,
- LayerView.DynamicToolbarListener,
- BrowserSearch.OnSearchListener,
- BrowserSearch.OnEditSuggestionListener,
- OnUrlOpenListener,
- OnUrlOpenInBackgroundListener,
- AnchoredPopup.OnVisibilityChangeListener,
- ActionModeCompat.Presenter,
- LayoutInflater.Factory {
+ implements TabsPanel.TabsLayoutChangeListener,
+ PropertyAnimator.PropertyAnimationListener,
+ View.OnKeyListener,
+ LayerView.DynamicToolbarListener,
+ BrowserSearch.OnSearchListener,
+ BrowserSearch.OnEditSuggestionListener,
+ OnUrlOpenListener,
+ OnUrlOpenInBackgroundListener,
+ AnchoredPopup.OnVisibilityChangeListener,
+ ActionModeCompat.Presenter,
+ LayoutInflater.Factory,
+ DeepLinkListener {
private static final String LOGTAG = "GeckoBrowserApp";
private static final int TABS_ANIMATION_DURATION = 450;
// Intent String extras used to specify custom Switchboard configurations.
private static final String INTENT_KEY_SWITCHBOARD_SERVER = "switchboard-server";
// TODO: Replace with kinto endpoint.
@@ -246,16 +253,44 @@ public class BrowserApp extends GeckoApp
private ActionModeCompat mActionMode;
private TabHistoryController tabHistoryController;
private ZoomedView mZoomedView;
private static final int GECKO_TOOLS_MENU = -1;
private static final int ADDON_MENU_OFFSET = 1000;
public static final String TAB_HISTORY_FRAGMENT_TAG = "tabHistoryFragment";
+ @Override
+ public void execute(DeepLinkAction action) {
+ if (action.getType() == DeepLinkAction.TYPE.DEFAULT_BROWSER) {
+ boolean isDefaultBrowser = getSharedPreferences().getBoolean(GeckoPreferences.PREFS_DEFAULT_BROWSER, false);
+ if (isDefaultBrowser(Intent.ACTION_VIEW)) {
+ return;
+ }
+ GeckoSharedPrefs.forApp(this).edit().putBoolean(GeckoPreferences.PREFS_DEFAULT_BROWSER, true);
+
+ if (AppConstants.Versions.feature24Plus) {
+ // We are special casing the link to set the default browser here: On old Android versions we
+ // link to a SUMO page but on new Android versions we can link to the default app settings where
+ // the user can actually set a default browser (Bug 1312686).
+ Intent changeDefaultApps = new Intent("android.settings.MANAGE_DEFAULT_APPS_SETTINGS");
+ getContext().startActivity(changeDefaultApps);
+ } else {
+ Tabs.getInstance().loadUrlInTab(getString(R.string.pref_default_browser_link));
+
+ }
+ }
+
+ }
+
+ @Override
+ public boolean isFinishing() {
+ return false;
+ }
+
private static class MenuItemInfo {
public int id;
public String label;
public boolean checkable;
public boolean checked;
public boolean enabled = true;
public boolean visible = true;
public int parent;
@@ -526,24 +561,25 @@ public class BrowserApp extends GeckoApp
return true;
case KeyEvent.KEYCODE_W:
Tabs.getInstance().closeTab(tab);
return true;
case KeyEvent.KEYCODE_F:
mFindInPageBar.show();
- return true;
+ return true;
}
}
return false;
}
private Runnable mCheckLongPress;
+
{
// Only initialise the runnable if we are >= N.
// See onKeyDown() for more details of the back-button long-press workaround
if (!Versions.preN) {
mCheckLongPress = new Runnable() {
public void run() {
handleBackLongPress();
}
@@ -580,16 +616,20 @@ public class BrowserApp extends GeckoApp
if (AndroidGamepadManager.handleKeyEvent(event)) {
return true;
}
return super.onKeyUp(keyCode, event);
}
@Override
public void onCreate(Bundle savedInstanceState) {
+
+
+ handleDeepLink();
+
final Context appContext = getApplicationContext();
GeckoLoader.loadMozGlue(appContext);
if (!HardwareUtils.isSupportedSystem() || !GeckoLoader.neonCompatible()) {
// This build does not support the Android version of the device; Exit early.
super.onCreate(savedInstanceState);
return;
}
@@ -727,48 +767,48 @@ public class BrowserApp extends GeckoApp
setBrowserToolbarListeners();
mFindInPageBar = (FindInPageBar) findViewById(R.id.find_in_page);
mMediaCastingBar = (MediaCastingBar) findViewById(R.id.media_casting);
mDoorhangerOverlay = findViewById(R.id.doorhanger_overlay);
EventDispatcher.getInstance().registerGeckoThreadListener(this,
- "Search:Keyword",
- null);
+ "Search:Keyword",
+ null);
EventDispatcher.getInstance().registerUiThreadListener(this,
- "Menu:Open",
- "Menu:Update",
- "Menu:Add",
- "Menu:Remove",
- "LightweightTheme:Update",
- "Tab:Added",
- "Video:Play",
- "CharEncoding:Data",
- "CharEncoding:State",
- "Settings:Show",
- "Updater:Launch",
- "Sanitize:OpenTabs",
- null);
+ "Menu:Open",
+ "Menu:Update",
+ "Menu:Add",
+ "Menu:Remove",
+ "LightweightTheme:Update",
+ "Tab:Added",
+ "Video:Play",
+ "CharEncoding:Data",
+ "CharEncoding:State",
+ "Settings:Show",
+ "Updater:Launch",
+ "Sanitize:OpenTabs",
+ null);
EventDispatcher.getInstance().registerBackgroundThreadListener(this,
- "Experiments:GetActive",
- "Experiments:SetOverride",
- "Experiments:ClearOverride",
- "Favicon:Request",
- "Feedback:MaybeLater",
- "Sanitize:ClearHistory",
- "Sanitize:ClearSyncedTabs",
- "Telemetry:Gather",
- "Download:AndroidDownloadManager",
- "Website:AppInstalled",
- "Website:AppInstallFailed",
- "Website:Metadata",
- null);
+ "Experiments:GetActive",
+ "Experiments:SetOverride",
+ "Experiments:ClearOverride",
+ "Favicon:Request",
+ "Feedback:MaybeLater",
+ "Sanitize:ClearHistory",
+ "Sanitize:ClearSyncedTabs",
+ "Telemetry:Gather",
+ "Download:AndroidDownloadManager",
+ "Website:AppInstalled",
+ "Website:AppInstallFailed",
+ "Website:Metadata",
+ null);
getAppEventDispatcher().registerUiThreadListener(this, "Prompt:ShowTop");
final GeckoProfile profile = getProfile();
// We want to upload the telemetry core ping as soon after startup as possible. It relies on the
// Distribution being initialized. If you move this initialization, ensure it plays well with telemetry.
final Distribution distribution = Distribution.init(getApplicationContext());
@@ -818,38 +858,50 @@ public class BrowserApp extends GeckoApp
// Set the maximum bits-per-pixel the favicon system cares about.
IconDirectoryEntry.setMaxBPP(GeckoAppShell.getScreenDepth());
// The update service is enabled for RELEASE_OR_BETA, which includes the release and beta channels.
// However, no updates are served. Therefore, we don't trust the update service directly, and
// try to avoid prompting unnecessarily. See Bug 1232798.
if (!AppConstants.RELEASE_OR_BETA && UpdateServiceHelper.isUpdaterEnabled(this)) {
Permissions.from(this)
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .doNotPrompt()
- .andFallback(new Runnable() {
- @Override
- public void run() {
- showUpdaterPermissionSnackbar();
- }
- })
- .run();
+ .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ .doNotPrompt()
+ .andFallback(new Runnable() {
+ @Override
+ public void run() {
+ showUpdaterPermissionSnackbar();
+ }
+ })
+ .run();
}
for (final BrowserAppDelegate delegate : delegates) {
delegate.onCreate(this, savedInstanceState);
}
// We want to get an understanding of how our user base is spread (bug 1221646).
final String installerPackageName = getPackageManager().getInstallerPackageName(getPackageName());
Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH, TelemetryContract.Method.SYSTEM, "installer_" + installerPackageName);
}
+ private void handleDeepLink() {
+ DeepLinkStore.register(DeepLinkAction.TYPE.DEFAULT_BROWSER, this);
+ Intent intent = getIntent();
+ if (intent != null && intent.getData() != null) {
+ String deepLink = DeepLinkUtil.getDeepLink(intent.getData().toString());
+ if (deepLink != null && deepLink.equalsIgnoreCase(DeepLinkAction.TYPE.DEFAULT_BROWSER.name())) {
+ DeepLinkStore.dispatch(new DeepLinkAction(DeepLinkAction.TYPE.DEFAULT_BROWSER, deepLink));
+ }
+ }
+ }
+
/**
* Initializes the default Switchboard URLs the first time.
+ *
* @param intent
*/
private static void initSwitchboard(final Context context, final SafeIntent intent, final boolean isInAutomation) {
if (isInAutomation) {
Log.d(LOGTAG, "Switchboard disabled - in automation");
return;
} else if (!AppConstants.MOZ_SWITCHBOARD) {
Log.d(LOGTAG, "Switchboard compile-time disabled");
@@ -886,19 +938,19 @@ public class BrowserApp extends GeckoApp
private void conditionallyNotifyEOL() {
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
try {
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
if (!prefs.contains(EOL_NOTIFIED)) {
// Launch main App to load SUMO url on EOL notification.
final String link = getString(R.string.eol_notification_url,
- AppConstants.MOZ_APP_VERSION,
- AppConstants.OS_TARGET,
- Locales.getLanguageTag(Locale.getDefault()));
+ AppConstants.MOZ_APP_VERSION,
+ AppConstants.OS_TARGET,
+ Locales.getLanguageTag(Locale.getDefault()));
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
intent.setData(Uri.parse(link));
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
final Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.eol_notification_title))
@@ -908,19 +960,19 @@ public class BrowserApp extends GeckoApp
.setContentIntent(pendingIntent)
.build();
final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final int notificationID = EOL_NOTIFIED.hashCode();
notificationManager.notify(notificationID, notification);
GeckoSharedPrefs.forProfile(this)
- .edit()
- .putBoolean(EOL_NOTIFIED, true)
- .apply();
+ .edit()
+ .putBoolean(EOL_NOTIFIED, true)
+ .apply();
}
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
}
/**
* Code to actually show the first run pager, separated
@@ -941,17 +993,17 @@ public class BrowserApp extends GeckoApp
}
}
/**
* Check and show the firstrun pane if the browser has never been launched and
* is not opening an external link from another application.
*
* @param context Context of application; used to show firstrun pane if appropriate
- * @param intent Intent that launched this activity
+ * @param intent Intent that launched this activity
*/
private void checkFirstrun(Context context, SafeIntent intent) {
if (getProfile().inGuestMode()) {
// We do not want to show any first run tour for guest profiles.
return;
}
if (intent.getBooleanExtra(EXTRA_SKIP_STARTPANE, false)) {
@@ -960,17 +1012,17 @@ public class BrowserApp extends GeckoApp
return;
}
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
try {
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
if (prefs.getBoolean(FirstrunAnimationContainer.PREF_FIRSTRUN_ENABLED_OLD, true) &&
- prefs.getBoolean(FirstrunAnimationContainer.PREF_FIRSTRUN_ENABLED, true)) {
+ prefs.getBoolean(FirstrunAnimationContainer.PREF_FIRSTRUN_ENABLED, true)) {
if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
// Check to see if a distribution has turned off the first run pager.
final Distribution distribution = Distribution.getInstance(BrowserApp.this);
if (!distribution.shouldWaitForSystemDistribution()) {
checkFirstrunInternal();
} else {
distribution.addOnDistributionReadyCallback(new Distribution.ReadyCallback() {
@Override
@@ -1422,17 +1474,17 @@ public class BrowserApp extends GeckoApp
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
GeckoAppShell.createShortcut(title, url);
}
});
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.CONTEXT_MENU,
- getResources().getResourceEntryName(itemId));
+ getResources().getResourceEntryName(itemId));
return true;
}
if (itemId == R.id.set_as_homepage) {
final Tab tab = Tabs.getInstance().getSelectedTab();
if (tab == null) {
return true;
}
@@ -1442,17 +1494,17 @@ public class BrowserApp extends GeckoApp
return true;
}
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
final SharedPreferences.Editor editor = prefs.edit();
editor.putString(GeckoPreferences.PREFS_HOMEPAGE, url);
editor.apply();
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.CONTEXT_MENU,
- getResources().getResourceEntryName(itemId));
+ getResources().getResourceEntryName(itemId));
return true;
}
return false;
}
@Override
public void setAccessibilityEnabled(boolean enabled) {
@@ -1503,48 +1555,48 @@ public class BrowserApp extends GeckoApp
if (mZoomedView != null) {
mZoomedView.destroy();
}
mSearchEngineManager.unregisterListeners();
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
- "Search:Keyword",
- null);
+ "Search:Keyword",
+ null);
EventDispatcher.getInstance().unregisterUiThreadListener(this,
- "Menu:Open",
- "Menu:Update",
- "Menu:Add",
- "Menu:Remove",
- "LightweightTheme:Update",
- "Tab:Added",
- "Video:Play",
- "CharEncoding:Data",
- "CharEncoding:State",
- "Settings:Show",
- "Updater:Launch",
- "Sanitize:OpenTabs",
- null);
+ "Menu:Open",
+ "Menu:Update",
+ "Menu:Add",
+ "Menu:Remove",
+ "LightweightTheme:Update",
+ "Tab:Added",
+ "Video:Play",
+ "CharEncoding:Data",
+ "CharEncoding:State",
+ "Settings:Show",
+ "Updater:Launch",
+ "Sanitize:OpenTabs",
+ null);
EventDispatcher.getInstance().unregisterBackgroundThreadListener(this,
- "Experiments:GetActive",
- "Experiments:SetOverride",
- "Experiments:ClearOverride",
- "Favicon:Request",
- "Feedback:MaybeLater",
- "Sanitize:ClearHistory",
- "Sanitize:ClearSyncedTabs",
- "Telemetry:Gather",
- "Download:AndroidDownloadManager",
- "Website:AppInstalled",
- "Website:AppInstallFailed",
- "Website:Metadata",
- null);
+ "Experiments:GetActive",
+ "Experiments:SetOverride",
+ "Experiments:ClearOverride",
+ "Favicon:Request",
+ "Feedback:MaybeLater",
+ "Sanitize:ClearHistory",
+ "Sanitize:ClearSyncedTabs",
+ "Telemetry:Gather",
+ "Download:AndroidDownloadManager",
+ "Website:AppInstalled",
+ "Website:AppInstallFailed",
+ "Website:Metadata",
+ null);
getAppEventDispatcher().unregisterUiThreadListener(this, "Prompt:ShowTop");
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,
// because the source code looks like it will only do this
@@ -1582,18 +1634,18 @@ public class BrowserApp extends GeckoApp
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
GeckoThread.waitOnGecko();
}
if (mRestartIntent != null) {
// Restarting, so let Restarter kill us.
final Intent intent = new Intent();
intent.setClass(getApplicationContext(), Restarter.class)
- .putExtra("pid", Process.myPid())
- .putExtra(Intent.EXTRA_INTENT, mRestartIntent);
+ .putExtra("pid", Process.myPid())
+ .putExtra(Intent.EXTRA_INTENT, mRestartIntent);
startService(intent);
} else {
// Exiting, so kill our own process.
Process.killProcess(Process.myPid());
}
}
@Override
@@ -1671,31 +1723,31 @@ public class BrowserApp extends GeckoApp
if (mFormAssistPopup != null) {
mFormAssistPopup.onMetricsChanged(aMetrics);
}
}
@Override
public void onPanZoomStopped() {
if (!mDynamicToolbar.isEnabled() || isHomePagerVisible() ||
- mBrowserChrome.getVisibility() != View.VISIBLE) {
+ mBrowserChrome.getVisibility() != View.VISIBLE) {
return;
}
// Make sure the toolbar is fully hidden or fully shown when the user
// lifts their finger, depending on various conditions.
ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics();
float toolbarTranslation = mLayerView.getDynamicToolbarAnimator().getToolbarTranslation();
boolean shortPage = metrics.getPageHeight() < metrics.getHeight();
boolean atBottomOfLongPage =
- FloatUtils.fuzzyEquals(metrics.pageRectBottom, metrics.viewportRectBottom())
- && (metrics.pageRectBottom > 2 * metrics.getHeight());
+ FloatUtils.fuzzyEquals(metrics.pageRectBottom, metrics.viewportRectBottom())
+ && (metrics.pageRectBottom > 2 * metrics.getHeight());
Log.v(LOGTAG, "On pan/zoom stopped, short page: " + shortPage
- + "; atBottomOfLongPage: " + atBottomOfLongPage);
+ + "; atBottomOfLongPage: " + atBottomOfLongPage);
if (shortPage || atBottomOfLongPage) {
mDynamicToolbar.setVisible(true, VisibilityTransition.ANIMATE);
}
}
public void refreshToolbarHeight() {
ThreadUtils.assertOnUiThread();
@@ -1851,17 +1903,17 @@ public class BrowserApp extends GeckoApp
if (mBrowserToolbar.isEditing()) {
mBrowserToolbar.cancelEdit();
}
openOptionsMenu();
break;
case "Menu:Update":
updateAddonMenuItem(message.getInt("id") + ADDON_MENU_OFFSET,
- message.getBundle("options"));
+ message.getBundle("options"));
break;
case "Menu:Add":
final MenuItemInfo info = new MenuItemInfo();
info.label = message.getString("name");
info.id = message.getInt("id") + ADDON_MENU_OFFSET;
info.checked = message.getBoolean("checked", false);
info.enabled = message.getBoolean("enabled", true);
@@ -1885,17 +1937,17 @@ public class BrowserApp extends GeckoApp
recordSearch(GeckoSharedPrefs.forProfile(this), message.getString("identifier"),
TelemetryContract.Method.ACTIONBAR);
break;
case "Prompt:ShowTop":
// Bring this activity to front so the prompt is visible..
Intent bringToFrontIntent = new Intent();
bringToFrontIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
- AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
+ AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
bringToFrontIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(bringToFrontIntent);
break;
case "Tab:Added":
if (message.getBoolean("cancelEditMode")) {
// Set the target tab to null so it does not get selected (on editing
// mode exit) in lieu of the tab that we're going to open and select.
@@ -1903,17 +1955,17 @@ public class BrowserApp extends GeckoApp
mBrowserToolbar.cancelEdit();
}
break;
case "Video:Play":
if (SwitchBoard.isInExperiment(this, Experiments.HLS_VIDEO_PLAYBACK)) {
mVideoPlayer.start(Uri.parse(message.getString("uri")));
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW,
- TelemetryContract.Method.CONTENT, "playhls");
+ TelemetryContract.Method.CONTENT, "playhls");
}
break;
case "CharEncoding:Data":
final GeckoBundle[] charsets = message.getBundleArray("charsets");
final int selected = message.getInt("selected");
final String[] titleArray = new String[charsets.length];
@@ -1955,17 +2007,17 @@ public class BrowserApp extends GeckoApp
case "Experiments:GetActive":
final List<String> experiments = SwitchBoard.getActiveExperiments(this);
callback.sendSuccess(experiments.toArray(new String[experiments.size()]));
break;
case "Experiments:SetOverride":
Experiments.setOverride(getContext(), message.getString("name"),
- message.getBoolean("isEnabled"));
+ message.getBoolean("isEnabled"));
break;
case "Experiments:ClearOverride":
Experiments.clearOverride(getContext(), message.getString("name"));
break;
case "Favicon:Request":
final String url = message.getString("url");
@@ -2029,40 +2081,40 @@ public class BrowserApp extends GeckoApp
Telemetry.addToHistogram("BROWSER_IS_USER_DEFAULT",
(isDefaultBrowser(Intent.ACTION_VIEW) ? 1 : 0));
Telemetry.addToHistogram("FENNEC_CUSTOM_HOMEPAGE",
(TextUtils.isEmpty(Tabs.getHomepage(this)) ? 0 : 1));
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(getContext());
final boolean hasCustomHomepanels =
prefs.contains(HomeConfigPrefsBackend.PREFS_CONFIG_KEY) ||
- prefs.contains(HomeConfigPrefsBackend.PREFS_CONFIG_KEY_OLD);
+ prefs.contains(HomeConfigPrefsBackend.PREFS_CONFIG_KEY_OLD);
Telemetry.addToHistogram("FENNEC_HOMEPANELS_CUSTOM", hasCustomHomepanels ? 1 : 0);
Telemetry.addToHistogram("FENNEC_READER_VIEW_CACHE_SIZE",
SavedReaderViewHelper.getSavedReaderViewHelper(getContext())
- .getDiskSpacedUsedKB());
+ .getDiskSpacedUsedKB());
if (Versions.feature16Plus) {
Telemetry.addToHistogram("BROWSER_IS_ASSIST_DEFAULT",
(isDefaultBrowser(Intent.ACTION_ASSIST) ? 1 : 0));
}
Telemetry.addToHistogram("FENNEC_ORBOT_INSTALLED",
- ContextUtils.isPackageInstalled(getContext(), "org.torproject.android") ? 1 : 0);
+ ContextUtils.isPackageInstalled(getContext(), "org.torproject.android") ? 1 : 0);
break;
case "Website:AppInstalled":
final String name = message.getString("name");
final String startUrl = message.getString("start_url");
final String manifestPath = message.getString("manifest_path");
final Bitmap icon = FaviconDecoder
- .decodeDataURI(getContext(), message.getString("icon"))
- .getBestBitmap(GeckoAppShell.getPreferredIconSize());
+ .decodeDataURI(getContext(), message.getString("icon"))
+ .getBestBitmap(GeckoAppShell.getPreferredIconSize());
createAppShortcut(name, startUrl, manifestPath, icon);
break;
case "Website:AppInstallFailed":
final String title = message.getString("title");
final String bookmarkUrl = message.getString("url");
createBrowserShortcut(title, bookmarkUrl);
break;
@@ -2129,17 +2181,17 @@ public class BrowserApp extends GeckoApp
final String location = message.getString("location");
final boolean hasImage = message.getBoolean("hasImage");
final String metadata = message.getString("metadata");
final ContentProviderClient contentProviderClient = getContentResolver()
.acquireContentProviderClient(BrowserContract.PageMetadata.CONTENT_URI);
if (contentProviderClient == null) {
Log.w(LOGTAG, "Failed to obtain content provider client for: " +
- BrowserContract.PageMetadata.CONTENT_URI);
+ BrowserContract.PageMetadata.CONTENT_URI);
return;
}
try {
GlobalPageMetadata.getInstance().add(
BrowserDB.from(getProfile()),
contentProviderClient,
location, hasImage, metadata);
} finally {
@@ -2199,20 +2251,21 @@ public class BrowserApp extends GeckoApp
public void showNormalTabs() {
showTabs(TabsPanel.Panel.NORMAL_TABS);
}
@Override
public void showPrivateTabs() {
showTabs(TabsPanel.Panel.PRIVATE_TABS);
}
+
/**
- * Ensure the TabsPanel view is properly inflated and returns
- * true when the view has been inflated, false otherwise.
- */
+ * Ensure the TabsPanel view is properly inflated and returns
+ * true when the view has been inflated, false otherwise.
+ */
private boolean ensureTabsPanelExists() {
if (mTabsPanel != null) {
return false;
}
ViewStub tabsPanelStub = (ViewStub) findViewById(R.id.tabs_panel);
mTabsPanel = (TabsPanel) tabsPanelStub.inflate();
@@ -2289,17 +2342,17 @@ public class BrowserApp extends GeckoApp
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onTabsLayoutChange(int width, int height) {
int animationLength = TABS_ANIMATION_DURATION;
if (mMainLayoutAnimator != null) {
- animationLength = Math.max(1, animationLength - (int)mMainLayoutAnimator.getRemainingTime());
+ animationLength = Math.max(1, animationLength - (int) mMainLayoutAnimator.getRemainingTime());
mMainLayoutAnimator.stop(false);
}
if (areTabsShown()) {
mTabsPanel.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
// Hide the web content from accessibility tools even though it's visible
// so that you can't examine it as long as the tabs are being shown.
if (Versions.feature16Plus) {
@@ -2309,18 +2362,18 @@ public class BrowserApp extends GeckoApp
if (Versions.feature16Plus) {
mLayerView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
}
mMainLayoutAnimator = new PropertyAnimator(animationLength, sTabsInterpolator);
mMainLayoutAnimator.addPropertyAnimationListener(this);
mMainLayoutAnimator.attach(mMainLayout,
- PropertyAnimator.Property.SCROLL_Y,
- -height);
+ PropertyAnimator.Property.SCROLL_Y,
+ -height);
mTabsPanel.prepareTabsAnimation(mMainLayoutAnimator);
mBrowserToolbar.triggerTabsPanelTransition(mMainLayoutAnimator, areTabsShown());
// If the tabs panel is animating onto the screen, pin the dynamic
// toolbar.
if (mDynamicToolbar.isEnabled()) {
if (width > 0 && height > 0) {
@@ -2362,19 +2415,19 @@ public class BrowserApp extends GeckoApp
}
/**
* Attempts to switch to an open tab with the given URL.
* <p>
* If the tab exists, this method cancels any in-progress editing as well as
* calling {@link Tabs#selectTab(int)}.
*
- * @param url of tab to switch to.
+ * @param url of tab to switch to.
* @param flags to obey: if {@link OnUrlOpenListener.Flags#ALLOW_SWITCH_TO_TAB}
- * is not present, return false.
+ * is not present, return false.
* @return true if we successfully switched to a tab, false otherwise.
*/
private boolean maybeSwitchToTab(String url, EnumSet<OnUrlOpenListener.Flags> flags) {
if (!flags.contains(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB)) {
return false;
}
final Tabs tabs = Tabs.getInstance();
@@ -2524,17 +2577,17 @@ public class BrowserApp extends GeckoApp
}
private void commitEditingMode() {
if (!mBrowserToolbar.isEditing()) {
return;
}
Telemetry.stopUISession(TelemetryContract.Session.AWESOMESCREEN,
- TelemetryContract.Reason.COMMIT);
+ TelemetryContract.Reason.COMMIT);
final String url = mBrowserToolbar.commitEdit();
// HACK: We don't know the url that will be loaded when hideHomePager is initially called
// in BrowserToolbar's onStopEditing listener so on the awesomescreen, hideHomePager will
// use the url "about:home" and return without taking any action. hideBrowserSearch is
// then called, but since hideHomePager changes both HomePager and LayerView visibility
// and exited without taking an action, no Views are displayed and graphical corruption is
@@ -2600,40 +2653,39 @@ public class BrowserApp extends GeckoApp
// Otherwise, construct a search query from the bookmark keyword.
// Replace lower case bookmark keywords with URLencoded search query or
// replace upper case bookmark keywords with un-encoded search query.
// This makes it match the same behaviour as on Firefox for the desktop.
final String searchUrl = keywordUrl.replace("%s", URLEncoder.encode(keywordSearch)).replace("%S", keywordSearch);
Tabs.getInstance().loadUrl(searchUrl, Tabs.LOADURL_USER_ENTERED);
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL,
- TelemetryContract.Method.ACTIONBAR,
- "keyword");
+ TelemetryContract.Method.ACTIONBAR,
+ "keyword");
}
});
}
/**
* Records in telemetry that a search has occurred.
*
* @param where where the search was started from
*/
private static void recordSearch(@NonNull final SharedPreferences prefs, @NonNull final String engineIdentifier,
- @NonNull final TelemetryContract.Method where) {
+ @NonNull final TelemetryContract.Method where) {
// We could include the engine identifier as an extra but we'll
// just capture that with core ping telemetry (bug 1253319).
Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH, where);
SearchCountMeasurements.incrementSearch(prefs, engineIdentifier, where.toString());
}
/**
* Store search query in SearchHistoryProvider.
*
- * @param query
- * a search query to store. We won't store empty queries.
+ * @param query a search query to store. We won't store empty queries.
*/
private void storeSearchQuery(final String query) {
if (TextUtils.isEmpty(query)) {
return;
}
// Filter out URLs and long suggestions
if (query.length() > 50 || Pattern.matches("^(https?|ftp|file)://.*", query)) {
@@ -2662,21 +2714,21 @@ public class BrowserApp extends GeckoApp
showBrowserSearch();
mBrowserSearch.filter(searchTerm, handler);
}
}
/**
* Selects the target tab for editing mode. This is expected to be the tab selected on editing
* mode entry, unless it is subsequently overridden.
- *
+ * <p>
* A background tab may be selected while editing mode is active (e.g. popups), causing the
* new url to load in the newly selected tab. Call this method on editing mode exit to
* mitigate this.
- *
+ * <p>
* Note that this method is disabled for new tablets because we can see the selected tab in the
* tab strip and, when the selected tab changes during editing mode as in this hack, the
* temporarily selected tab is visible to users.
*/
private void selectTargetTabForEditingMode() {
if (HardwareUtils.isTablet()) {
return;
}
@@ -2798,17 +2850,17 @@ public class BrowserApp extends GeckoApp
if (mFirstrunAnimationContainer == null) {
final ViewStub firstrunPagerStub = (ViewStub) findViewById(R.id.firstrun_pager_stub);
mFirstrunAnimationContainer = (FirstrunAnimationContainer) firstrunPagerStub.inflate();
mFirstrunAnimationContainer.load(getApplicationContext(), getSupportFragmentManager());
mFirstrunAnimationContainer.registerOnFinishListener(new FirstrunAnimationContainer.OnFinishListener() {
@Override
public void onFinish() {
if (mFirstrunAnimationContainer.showBrowserHint() &&
- TextUtils.isEmpty(Tabs.getHomepage(BrowserApp.this))) {
+ TextUtils.isEmpty(Tabs.getHomepage(BrowserApp.this))) {
enterEditingMode();
}
}
});
}
mHomeScreenContainer.setVisibility(View.VISIBLE);
}
@@ -2836,17 +2888,17 @@ public class BrowserApp extends GeckoApp
// Show the toolbar before hiding about:home so the
// onMetricsChanged callback still works.
if (mDynamicToolbar.isEnabled()) {
mDynamicToolbar.setVisible(true, VisibilityTransition.IMMEDIATE);
}
if (mHomeScreen == null) {
if (ActivityStream.isEnabled(this) &&
- !ActivityStream.isHomePanel()) {
+ !ActivityStream.isHomePanel()) {
final ViewStub asStub = (ViewStub) findViewById(R.id.activity_stream_stub);
mHomeScreen = (HomeScreen) asStub.inflate();
} else {
final ViewStub homePagerStub = (ViewStub) findViewById(R.id.home_pager_stub);
mHomeScreen = (HomeScreen) homePagerStub.inflate();
// For now these listeners are HomePager specific. In future we might want
// to have a more abstracted data storage, with one Bundle containing all
@@ -2897,20 +2949,20 @@ public class BrowserApp extends GeckoApp
mHomeScreenContainer.removeView(homeBanner);
}
});
}
}
mHomeScreenContainer.setVisibility(View.VISIBLE);
mHomeScreen.load(getSupportLoaderManager(),
- getSupportFragmentManager(),
- panelId,
- panelRestoreData,
- animator);
+ getSupportFragmentManager(),
+ panelId,
+ panelRestoreData,
+ animator);
// Hide the web content so it cannot be focused by screen readers.
hideWebContentOnPropertyAnimationEnd(animator);
}
private void hideWebContentOnPropertyAnimationEnd(final PropertyAnimator animator) {
if (animator == null) {
hideWebContent();
@@ -2935,16 +2987,17 @@ public class BrowserApp extends GeckoApp
private void hideWebContent() {
// The view is set to INVISIBLE, rather than GONE, to avoid
// the additional requestLayout() call.
mLayerView.setVisibility(View.INVISIBLE);
}
/**
* Hide the Onboarding pager on user action, and don't show any onFinish hints.
+ *
* @param method TelemetryContract method by which action was taken
* @return boolean of whether pager was visible
*/
private boolean hideFirstrunPager(TelemetryContract.Method method) {
if (!isFirstrunVisible()) {
return false;
}
@@ -3179,20 +3232,20 @@ public class BrowserApp extends GeckoApp
addAddonMenuItemToMenu(mMenu, info);
}
private void removeAddonMenuItem(int id) {
// Remove add-on menu item from cache, if available.
if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) {
for (MenuItemInfo item : mAddonMenuItemsCache) {
- if (item.id == id) {
- mAddonMenuItemsCache.remove(item);
- break;
- }
+ if (item.id == id) {
+ mAddonMenuItemsCache.remove(item);
+ break;
+ }
}
}
if (mMenu == null)
return;
final MenuItem menuItem = mMenu.findItem(id);
if (menuItem != null)
@@ -3231,17 +3284,17 @@ public class BrowserApp extends GeckoApp
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Sets mMenu = menu.
super.onCreateOptionsMenu(menu);
// Inform the menu about the action-items bar.
if (menu instanceof GeckoMenu &&
- HardwareUtils.isTablet()) {
+ HardwareUtils.isTablet()) {
((GeckoMenu) menu).setActionItemBarPresenter(mBrowserToolbar);
}
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.browser_app_menu, mMenu);
// Add add-on menu items, if any exist.
if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) {
@@ -3362,20 +3415,20 @@ public class BrowserApp extends GeckoApp
final 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.
// (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 boolean visible = HardwareUtils.isTelevision() ||
- prefs.getBoolean(GeckoPreferences.PREFS_SHOW_QUIT_MENU, false) ||
- !PrefUtils.getStringSet(prefs,
- ClearOnShutdownPref.PREF,
- new HashSet<String>()).isEmpty();
+ prefs.getBoolean(GeckoPreferences.PREFS_SHOW_QUIT_MENU, false) ||
+ !PrefUtils.getStringSet(prefs,
+ ClearOnShutdownPref.PREF,
+ new HashSet<String>()).isEmpty();
aMenu.findItem(R.id.quit).setVisible(visible);
// If tab data is unavailable we disable most of the context menu and related items and
// return early.
if (tab == null || tab.getURL() == null) {
bookmark.setEnabled(false);
back.setEnabled(false);
forward.setEnabled(false);
@@ -3524,18 +3577,18 @@ public class BrowserApp extends GeckoApp
}
}
final boolean privateTabVisible = Restrictions.isAllowed(this, Restrictable.PRIVATE_BROWSING);
MenuUtils.safeSetVisible(aMenu, R.id.new_private_tab, privateTabVisible);
// Disable PDF generation (save and print) for about:home and xul pages.
boolean allowPDF = (!(isAboutHome(tab) ||
- tab.getContentType().equals("application/vnd.mozilla.xul+xml") ||
- tab.getContentType().startsWith("video/")));
+ tab.getContentType().equals("application/vnd.mozilla.xul+xml") ||
+ tab.getContentType().startsWith("video/")));
saveAsPDF.setEnabled(allowPDF);
print.setEnabled(allowPDF);
print.setVisible(Versions.feature19Plus);
// Disable find in page for about:home, since it won't work on Java content.
findInPage.setEnabled(!isAboutHome(tab));
charEncoding.setVisible(GeckoPreferences.getCharEncodingState());
@@ -3802,18 +3855,18 @@ public class BrowserApp extends GeckoApp
GuestSession.hideNotification(context);
}
doRestart();
}
});
Resources res = getResources();
ps.setButtons(new String[] {
- res.getString(R.string.guest_session_dialog_continue),
- res.getString(R.string.guest_session_dialog_cancel)
+ res.getString(R.string.guest_session_dialog_continue),
+ res.getString(R.string.guest_session_dialog_cancel)
});
int titleString = 0;
int msgString = 0;
if (type == GuestModeDialog.ENTERING) {
titleString = R.string.new_guest_session_title;
msgString = R.string.new_guest_session_text;
} else {
@@ -3830,17 +3883,17 @@ public class BrowserApp extends GeckoApp
private boolean handleBackLongPress() {
// If the tab search history is already shown, do nothing.
TabHistoryFragment frag = (TabHistoryFragment) getSupportFragmentManager().findFragmentByTag(TAB_HISTORY_FRAGMENT_TAG);
if (frag != null) {
return true;
}
Tab tab = Tabs.getInstance().getSelectedTab();
- if (tab != null && !tab.isEditing()) {
+ if (tab != null && !tab.isEditing()) {
return tabHistoryController.showTabHistory(tab, TabHistoryController.HistoryAction.ALL);
}
return false;
}
/**
* This will detect if the key pressed is back. If so, will show the history.
@@ -3957,19 +4010,19 @@ public class BrowserApp extends GeckoApp
}
private void showTabQueuePromptIfApplicable(final SafeIntent intent) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
// We only want to show the prompt if the browser has been opened from an external url
if (TabQueueHelper.TAB_QUEUE_ENABLED && mInitialized
- && Intent.ACTION_VIEW.equals(intent.getAction())
- && !intent.getBooleanExtra(BrowserContract.SKIP_TAB_QUEUE_FLAG, false)
- && TabQueueHelper.shouldShowTabQueuePrompt(BrowserApp.this)) {
+ && Intent.ACTION_VIEW.equals(intent.getAction())
+ && !intent.getBooleanExtra(BrowserContract.SKIP_TAB_QUEUE_FLAG, false)
+ && TabQueueHelper.shouldShowTabQueuePrompt(BrowserApp.this)) {
Intent promptIntent = new Intent(BrowserApp.this, TabQueuePrompt.class);
startActivityForResult(promptIntent, ACTIVITY_REQUEST_TAB_QUEUE);
}
}
});
}
// HomePager.OnUrlOpenListener
@@ -4068,17 +4121,19 @@ public class BrowserApp extends GeckoApp
// BrowserSearch.OnEditSuggestionListener
@Override
public void onEditSuggestion(String suggestion) {
mBrowserToolbar.onEditSuggestion(suggestion);
}
@Override
- public int getLayout() { return R.layout.gecko_app; }
+ public int getLayout() {
+ return R.layout.gecko_app;
+ }
public SearchEngineManager getSearchEngineManager() {
return mSearchEngineManager;
}
// For use from tests only.
@RobocopTarget
public ReadingListHelper getReadingListHelper() {
@@ -4125,21 +4180,25 @@ public class BrowserApp extends GeckoApp
// Only slide the urlbar out if it was hidden when the action mode started
// Don't animate hiding it so that there's no flash as we switch back to url mode
mDynamicToolbar.setTemporarilyVisible(false, VisibilityTransition.IMMEDIATE);
}
public static interface TabStripInterface {
public void refresh();
- /** Called to let the tab strip know it is now, or is now no longer, being hidden by
- * something being drawn over it.
+
+ /**
+ * Called to let the tab strip know it is now, or is now no longer, being hidden by
+ * something being drawn over it.
*/
void tabStripIsCovered(boolean covered);
+
void setOnTabChangedListener(OnTabAddedOrRemovedListener listener);
+
interface OnTabAddedOrRemovedListener {
void onTabChanged();
}
}
@Override
protected void recordStartupActionTelemetry(final String passedURL, final String action) {
final TelemetryContract.Method method;