Index: mobile/android/base/BrowserApp.java |
diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java |
index fbdc52ce3f56bc07c406a6bd0a2ef0f0a4f5300f..3c729296fdedd10ae2496f13ef9d6164770880a1 100644 |
--- a/mobile/android/base/BrowserApp.java |
+++ b/mobile/android/base/BrowserApp.java |
@@ -5,22 +5,6 @@ |
package org.mozilla.gecko; |
-import java.io.File; |
-import java.io.FileNotFoundException; |
-import java.lang.Override; |
-import java.lang.reflect.Field; |
-import java.lang.reflect.Method; |
-import java.net.URLEncoder; |
-import java.util.EnumSet; |
-import java.util.HashSet; |
-import java.util.List; |
-import java.util.Locale; |
-import java.util.Vector; |
- |
-import android.support.v4.app.Fragment; |
-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; |
@@ -30,7 +14,6 @@ import org.mozilla.gecko.animation.PropertyAnimator; |
import org.mozilla.gecko.animation.TransitionsTracker; |
import org.mozilla.gecko.animation.ViewHelper; |
import org.mozilla.gecko.db.BrowserContract.Combined; |
-import org.mozilla.gecko.db.BrowserContract.SearchHistory; |
import org.mozilla.gecko.db.BrowserDB; |
import org.mozilla.gecko.db.SuggestedSites; |
import org.mozilla.gecko.distribution.Distribution; |
@@ -38,6 +21,7 @@ import org.mozilla.gecko.favicons.Favicons; |
import org.mozilla.gecko.favicons.LoadFaviconTask; |
import org.mozilla.gecko.favicons.OnFaviconLoadedListener; |
import org.mozilla.gecko.favicons.decoders.IconDirectoryEntry; |
+import org.mozilla.gecko.firstrun.FirstrunPane; |
import org.mozilla.gecko.fxa.FirefoxAccounts; |
import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity; |
import org.mozilla.gecko.gfx.BitmapUtils; |
@@ -54,22 +38,24 @@ import org.mozilla.gecko.home.HomePager; |
import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener; |
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener; |
import org.mozilla.gecko.home.HomePanelsManager; |
-import org.mozilla.gecko.home.TopSitesPanel; |
import org.mozilla.gecko.home.SearchEngine; |
import org.mozilla.gecko.menu.GeckoMenu; |
import org.mozilla.gecko.menu.GeckoMenuItem; |
import org.mozilla.gecko.mozglue.ContextUtils; |
+import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent; |
+import org.mozilla.gecko.mozglue.RobocopTarget; |
+import org.mozilla.gecko.overlays.ui.ShareDialog; |
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; |
+import org.mozilla.gecko.tabqueue.TabQueueHelper; |
import org.mozilla.gecko.tabs.TabHistoryController; |
+import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory; |
import org.mozilla.gecko.tabs.TabHistoryFragment; |
import org.mozilla.gecko.tabs.TabHistoryPage; |
import org.mozilla.gecko.tabs.TabsPanel; |
-import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory; |
-import org.mozilla.gecko.tiles.TilesRecorder; |
import org.mozilla.gecko.toolbar.AutocompleteHandler; |
import org.mozilla.gecko.toolbar.BrowserToolbar; |
import org.mozilla.gecko.toolbar.BrowserToolbar.TabEditingState; |
@@ -93,8 +79,7 @@ import org.mozilla.gecko.widget.GeckoActionProvider; |
import android.app.Activity; |
import android.app.AlertDialog; |
-import android.content.BroadcastReceiver; |
-import android.content.ContentValues; |
+import android.content.ContentResolver; |
import android.content.Context; |
import android.content.DialogInterface; |
import android.content.Intent; |
@@ -116,11 +101,12 @@ import android.nfc.NfcEvent; |
import android.os.Build; |
import android.os.Bundle; |
import android.os.StrictMode; |
-import android.support.v4.app.DialogFragment; |
+import android.support.v4.app.Fragment; |
import android.support.v4.app.FragmentManager; |
-import android.support.v4.content.LocalBroadcastManager; |
import android.text.TextUtils; |
import android.util.AttributeSet; |
+import android.util.Base64; |
+import android.util.Base64OutputStream; |
import android.util.Log; |
import android.view.InputDevice; |
import android.view.KeyEvent; |
@@ -140,6 +126,20 @@ import android.widget.ListView; |
import android.widget.RelativeLayout; |
import android.widget.Toast; |
import android.widget.ViewFlipper; |
+import org.json.JSONException; |
+import org.json.JSONObject; |
+ |
+import java.io.ByteArrayOutputStream; |
+import java.io.File; |
+import java.io.FileNotFoundException; |
+import java.io.IOException; |
+import java.lang.reflect.Method; |
+import java.net.URLEncoder; |
+import java.util.EnumSet; |
+import java.util.HashSet; |
+import java.util.List; |
+import java.util.Locale; |
+import java.util.Vector; |
public class BrowserApp extends GeckoApp |
implements TabsPanel.TabsLayoutChangeListener, |
@@ -154,6 +154,8 @@ public class BrowserApp extends GeckoApp |
LayoutInflater.Factory { |
private static final String LOGTAG = "GeckoBrowserApp"; |
+ private static final boolean ZOOMED_VIEW_ENABLED = AppConstants.NIGHTLY_BUILD; |
+ |
private static final int TABS_ANIMATION_DURATION = 450; |
private static final String ADD_SHORTCUT_TOAST = "add_shortcut_toast"; |
@@ -162,12 +164,12 @@ public class BrowserApp extends GeckoApp |
private static final String STATE_ABOUT_HOME_TOP_PADDING = "abouthome_top_padding"; |
private static final String BROWSER_SEARCH_TAG = "browser_search"; |
- private static final String ONBOARD_STARTPANE_TAG = "startpane_dialog"; |
// Request ID for startActivityForResult. |
private static final int ACTIVITY_REQUEST_PREFERENCES = 1001; |
- public static final String PREF_STARTPANE_ENABLED = "startpane_enabled"; |
+ @RobocopTarget |
+ public static final String EXTRA_SKIP_STARTPANE = "skipstartpane"; |
private BrowserSearch mBrowserSearch; |
private View mBrowserSearchContainer; |
@@ -179,17 +181,19 @@ public class BrowserApp extends GeckoApp |
// We can't name the TabStrip class because it's not included on API 9. |
private Refreshable mTabStrip; |
private ToolbarProgressView mProgressView; |
+ private FirstrunPane mFirstrunPane; |
private HomePager mHomePager; |
private TabsPanel mTabsPanel; |
private ViewGroup mHomePagerContainer; |
- protected Telemetry.Timer mAboutHomeStartupTimer; |
private ActionModeCompat mActionMode; |
private boolean mHideDynamicToolbarOnActionModeEnd; |
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"; |
+ |
private static class MenuItemInfo { |
public int id; |
public String label; |
@@ -237,8 +241,6 @@ public class BrowserApp extends GeckoApp |
private OrderedBroadcastHelper mOrderedBroadcastHelper; |
- private BroadcastReceiver mOnboardingReceiver; |
- |
private BrowserHealthReporter mBrowserHealthReporter; |
private ReadingListHelper mReadingListHelper; |
@@ -256,6 +258,175 @@ public class BrowserApp extends GeckoApp |
private final DynamicToolbar mDynamicToolbar = new DynamicToolbar(); |
+ private DragHelper mDragHelper; |
+ |
+ private class DragHelper implements OuterLayout.DragCallback { |
+ private int[] mToolbarLocation = new int[2]; // to avoid creation every time we need to check for toolbar location. |
+ // When dragging horizontally, the area of mainlayout between left drag bound and right drag bound can |
+ // be dragged. A touch on the right of that area will automatically close the view. |
+ private int mStatusBarHeight; |
+ |
+ public DragHelper() { |
+ // If a layout round happens from the root, the offset placed by viewdraghelper gets forgotten and |
+ // main layout gets replaced to offset 0. |
+ ((MainLayout) mMainLayout).setLayoutInterceptor(new LayoutInterceptor() { |
+ @Override |
+ public void onLayout() { |
+ if (mRootLayout.isMoving()) { |
+ mRootLayout.restoreTargetViewPosition(); |
+ } |
+ } |
+ }); |
+ } |
+ |
+ @Override |
+ public void onDragProgress(float progress) { |
+ mBrowserToolbar.setToolBarButtonsAlpha(1.0f - progress); |
+ mTabsPanel.translateInRange(progress); |
+ } |
+ |
+ @Override |
+ public View getViewToDrag() { |
+ return mMainLayout; |
+ } |
+ |
+ /** |
+ * Since pressing the tabs button slides the main layout, whereas draghelper changes its offset, here we |
+ * restore the position of mainlayout as if it was opened by pressing the button. This allows the closing |
+ * mechanism to work. |
+ */ |
+ @Override |
+ public void startDrag(boolean wasOpen) { |
+ if (wasOpen) { |
+ mTabsPanel.setHWLayerEnabled(true); |
+ mMainLayout.offsetTopAndBottom(getDragRange()); |
+ mMainLayout.scrollTo(0, 0); |
+ } else { |
+ prepareTabsToShow(); |
+ mBrowserToolbar.hideVirtualKeyboard(); |
+ } |
+ mBrowserToolbar.setContextMenuEnabled(false); |
+ } |
+ |
+ @Override |
+ public void stopDrag(boolean stoppingToOpen) { |
+ if (stoppingToOpen) { |
+ mTabsPanel.setHWLayerEnabled(false); |
+ mMainLayout.offsetTopAndBottom(-getDragRange()); |
+ mMainLayout.scrollTo(0, -getDragRange()); |
+ } else { |
+ mTabsPanel.hideImmediately(); |
+ mTabsPanel.setHWLayerEnabled(false); |
+ } |
+ // Re-enabling context menu only while stopping to close. |
+ if (stoppingToOpen) { |
+ mBrowserToolbar.setContextMenuEnabled(false); |
+ } else { |
+ mBrowserToolbar.setContextMenuEnabled(true); |
+ } |
+ } |
+ |
+ @Override |
+ public int getDragRange() { |
+ return mTabsPanel.getVerticalPanelHeight(); |
+ } |
+ |
+ @Override |
+ public int getOrderedChildIndex(int index) { |
+ // See ViewDragHelper's findTopChildUnder method. ViewDragHelper looks for the topmost view in z order |
+ // to understand what needs to be dragged. Here we are tampering Toast's index in case it's hidden, |
+ // otherwise draghelper would try to drag it. |
+ int mainLayoutIndex = mRootLayout.indexOfChild(mMainLayout); |
+ if (index > mainLayoutIndex && (mToast == null || !mToast.isVisible())) { |
+ return mainLayoutIndex; |
+ } else { |
+ return index; |
+ } |
+ } |
+ |
+ @Override |
+ public boolean canDrag(MotionEvent event) { |
+ if (!AppConstants.MOZ_DRAGGABLE_URLBAR) { |
+ return false; |
+ } |
+ |
+ // if no current tab is active. |
+ if (Tabs.getInstance().getSelectedTab() == null) { |
+ return false; |
+ } |
+ |
+ // currently disabled for tablets. |
+ if (HardwareUtils.isTablet()) { |
+ return false; |
+ } |
+ |
+ // not enabled in editing mode. |
+ if (mBrowserToolbar.isEditing()) { |
+ return false; |
+ } |
+ |
+ return isInToolbarBounds((int) event.getRawY()); |
+ } |
+ |
+ @Override |
+ public boolean canInterceptEventWhileOpen(MotionEvent event) { |
+ if (event.getActionMasked() != MotionEvent.ACTION_DOWN) { |
+ return false; |
+ } |
+ |
+ // Need to check if are intercepting a touch on main layout since we might hit a visible toast. |
+ if (mRootLayout.findTopChildUnder(event) == mMainLayout && |
+ isInToolbarBounds((int) event.getRawY())) { |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ private boolean isInToolbarBounds(int y) { |
+ mBrowserToolbar.getLocationOnScreen(mToolbarLocation); |
+ final int upperLimit = mToolbarLocation[1] + mBrowserToolbar.getMeasuredHeight(); |
+ final int lowerLimit = mToolbarLocation[1]; |
+ return (y > lowerLimit && y < upperLimit); |
+ } |
+ |
+ public void prepareTabsToShow() { |
+ if (ensureTabsPanelExists()) { |
+ // If we've just inflated the tabs panel, only show it once the current |
+ // layout pass is done to avoid displayed temporary UI states during |
+ // relayout. |
+ final ViewTreeObserver vto = mTabsPanel.getViewTreeObserver(); |
+ if (vto.isAlive()) { |
+ vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { |
+ @Override |
+ public void onGlobalLayout() { |
+ mTabsPanel.getViewTreeObserver().removeGlobalOnLayoutListener(this); |
+ prepareTabsToShow(); |
+ } |
+ }); |
+ } |
+ } else { |
+ mTabsPanel.prepareToDrag(); |
+ } |
+ } |
+ |
+ public int getLowerLimit() { |
+ return getStatusBarHeight(); |
+ } |
+ |
+ private int getStatusBarHeight() { |
+ if (mStatusBarHeight != 0) { |
+ return mStatusBarHeight; |
+ } |
+ final int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); |
+ if (resourceId > 0) { |
+ mStatusBarHeight = getResources().getDimensionPixelSize(resourceId); |
+ return mStatusBarHeight; |
+ } |
+ Log.e(LOGTAG, "Unable to find statusbar height"); |
+ return 0; |
+ } |
+ } |
+ |
@Override |
public View onCreateView(final String name, final Context context, final AttributeSet attrs) { |
final View view; |
@@ -330,7 +501,7 @@ public class BrowserApp extends GeckoApp |
break; |
} |
- if (NewTabletUI.isEnabled(this) && msg == TabEvents.SELECTED) { |
+ if (HardwareUtils.isTablet() && msg == TabEvents.SELECTED) { |
updateEditingModeForTab(tab); |
} |
@@ -493,10 +664,14 @@ public class BrowserApp extends GeckoApp |
@Override |
public void onCreate(Bundle savedInstanceState) { |
- mAboutHomeStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_ABOUTHOME"); |
- |
final Intent intent = getIntent(); |
+ |
+ // Note that we're calling GeckoProfile.get *before GeckoApp.onCreate*. |
+ // This means we're reliant on the logic in GeckoProfile to correctly |
+ // look up our launch intent (via BrowserApp's Activity-ness) and pull |
+ // out the arguments. Be careful if you change that! |
final GeckoProfile p = GeckoProfile.get(this); |
+ |
if (p != null && !p.inGuestMode()) { |
// This is *only* valid because we never want to use the guest mode |
// profile concurrently with a normal profile -- no syncing to it, |
@@ -548,7 +723,7 @@ public class BrowserApp extends GeckoApp |
GuestSession.handleIntent(this, intent); |
} |
- if (NewTabletUI.isEnabled(this)) { |
+ if (HardwareUtils.isTablet()) { |
mTabStrip = (Refreshable) (((ViewStub) findViewById(R.id.new_tablet_tab_strip)).inflate()); |
} |
@@ -598,6 +773,7 @@ public class BrowserApp extends GeckoApp |
"Accounts:Create", |
"CharEncoding:Data", |
"CharEncoding:State", |
+ "Favicon:CacheLoad", |
"Feedback:LastUrl", |
"Feedback:MaybeLater", |
"Feedback:OpenPlayStore", |
@@ -606,20 +782,20 @@ public class BrowserApp extends GeckoApp |
"Reader:Share", |
"Settings:Show", |
"Telemetry:Gather", |
- "Updater:Launch", |
- "BrowserToolbar:Visibility"); |
+ "Updater:Launch"); |
Distribution distribution = Distribution.init(this); |
// Init suggested sites engine in BrowserDB. |
final SuggestedSites suggestedSites = new SuggestedSites(appContext, distribution); |
- BrowserDB.setSuggestedSites(suggestedSites); |
+ final BrowserDB db = getProfile().getDB(); |
+ db.setSuggestedSites(suggestedSites); |
JavaAddonManager.getInstance().init(appContext); |
mSharedPreferencesHelper = new SharedPreferencesHelper(appContext); |
mOrderedBroadcastHelper = new OrderedBroadcastHelper(appContext); |
mBrowserHealthReporter = new BrowserHealthReporter(); |
- mReadingListHelper = new ReadingListHelper(appContext); |
+ mReadingListHelper = new ReadingListHelper(appContext, getProfile()); |
if (AppConstants.MOZ_ANDROID_BEAM) { |
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this); |
@@ -649,30 +825,42 @@ public class BrowserApp extends GeckoApp |
} |
}); |
+ mDragHelper = new DragHelper(); |
+ mRootLayout.setDraggableCallback(mDragHelper); |
+ |
// Set the maximum bits-per-pixel the favicon system cares about. |
IconDirectoryEntry.setMaxBPP(GeckoAppShell.getScreenDepth()); |
+ |
+ if (ZOOMED_VIEW_ENABLED) { |
+ ViewStub stub = (ViewStub) findViewById(R.id.zoomed_view_stub); |
+ mZoomedView = (ZoomedView) stub.inflate(); |
+ } |
} |
/** |
- * Check and show Onboarding start pane if Firefox has never been launched and |
+ * 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 Start Pane if appropriate |
- * @param intentAction Intent that launched this activity |
+ * @param context Context of application; used to show firstrun pane if appropriate |
+ * @param intent Intent that launched this activity |
*/ |
- private void checkStartPane(Context context, String intentAction) { |
+ private void checkFirstrun(Context context, SafeIntent intent) { |
+ if (intent.getBooleanExtra(EXTRA_SKIP_STARTPANE, false)) { |
+ // Note that we don't set the pref, so subsequent launches can result |
+ // in the firstrun pane being shown. |
+ return; |
+ } |
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); |
try { |
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this); |
- if (prefs.getBoolean(PREF_STARTPANE_ENABLED, false)) { |
- if (!Intent.ACTION_VIEW.equals(intentAction)) { |
- final DialogFragment dialog = new org.adblockplus.browser.StartPane(); |
- dialog.show(getSupportFragmentManager(), ONBOARD_STARTPANE_TAG); |
+ if (prefs.getBoolean(FirstrunPane.PREF_FIRSTRUN_ENABLED, false)) { |
+ if (!Intent.ACTION_VIEW.equals(intent.getAction())) { |
+ showFirstrunPager(); |
} |
// Don't bother trying again to show the v1 minimal first run. |
- prefs.edit().putBoolean(PREF_STARTPANE_ENABLED, false).apply(); |
+ prefs.edit().putBoolean(FirstrunPane.PREF_FIRSTRUN_ENABLED, false).apply(); |
} |
} finally { |
StrictMode.setThreadPolicy(savedPolicy); |
@@ -708,13 +896,31 @@ public class BrowserApp extends GeckoApp |
return; |
} |
+ if (hideFirstrunPager()) { |
+ Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL, TelemetryContract.Method.BACK, "firstrun-pane"); |
+ return; |
+ } |
+ |
super.onBackPressed(); |
} |
@Override |
public void onAttachedToWindow() { |
- // We can't show Onboarding until Gecko has finished initialization (bug 1077583). |
- checkStartPane(this, getIntent().getAction()); |
+ // We can't show the first run experience until Gecko has finished initialization (bug 1077583). |
Felix Dahlke
2015/07/22 16:19:18
lol, their term for this is even worse, "first run
|
+ checkFirstrun(this, new SafeIntent(getIntent())); |
+ } |
+ |
+ private void processTabQueue() { |
+ if (AppConstants.NIGHTLY_BUILD && AppConstants.MOZ_ANDROID_TAB_QUEUE) { |
+ ThreadUtils.postToBackgroundThread(new Runnable() { |
+ @Override |
+ public void run() { |
+ if (TabQueueHelper.shouldOpenTabQueueUrls(BrowserApp.this)) { |
+ TabQueueHelper.openQueuedUrls(BrowserApp.this, mProfile, TabQueueHelper.FILE_NAME); |
+ } |
+ } |
+ }); |
+ } |
} |
@Override |
@@ -735,6 +941,8 @@ public class BrowserApp extends GeckoApp |
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this, |
"Prompt:ShowTop"); |
+ |
+ processTabQueue(); |
} |
@Override |
@@ -743,9 +951,6 @@ public class BrowserApp extends GeckoApp |
// Register for Prompt:ShowTop so we can foreground this activity even if it's hidden. |
EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener)this, |
"Prompt:ShowTop"); |
- |
- final LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); |
- lbm.unregisterReceiver(mOnboardingReceiver); |
} |
@Override |
@@ -919,7 +1124,7 @@ public class BrowserApp extends GeckoApp |
if (enabled) { |
if (mLayerView != null) { |
- mLayerView.setOnMetricsChangedListener(this); |
+ mLayerView.setOnMetricsChangedDynamicToolbarViewportListener(this); |
} |
setToolbarMargin(0); |
mHomePagerContainer.setPadding(0, mBrowserChrome.getHeight(), 0, 0); |
@@ -927,7 +1132,7 @@ public class BrowserApp extends GeckoApp |
// Immediately show the toolbar when disabling the dynamic |
// toolbar. |
if (mLayerView != null) { |
- mLayerView.setOnMetricsChangedListener(null); |
+ mLayerView.setOnMetricsChangedDynamicToolbarViewportListener(null); |
} |
mHomePagerContainer.setPadding(0, 0, 0, 0); |
if (mBrowserChrome != null) { |
@@ -1098,6 +1303,9 @@ public class BrowserApp extends GeckoApp |
mReadingListHelper.uninit(); |
mReadingListHelper = null; |
} |
+ if (mZoomedView != null) { |
+ mZoomedView.destroy(); |
+ } |
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this, |
"Menu:Open", |
@@ -1110,6 +1318,7 @@ public class BrowserApp extends GeckoApp |
"Accounts:Create", |
"CharEncoding:Data", |
"CharEncoding:State", |
+ "Favicon:CacheLoad", |
"Feedback:LastUrl", |
"Feedback:MaybeLater", |
"Feedback:OpenPlayStore", |
@@ -1118,8 +1327,7 @@ public class BrowserApp extends GeckoApp |
"Reader:Share", |
"Settings:Show", |
"Telemetry:Gather", |
- "Updater:Launch", |
- "BrowserToolbar:Visibility"); |
+ "Updater:Launch"); |
if (AppConstants.MOZ_ANDROID_BEAM) { |
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this); |
@@ -1175,16 +1383,6 @@ public class BrowserApp extends GeckoApp |
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST); |
} |
- @Override |
- protected void loadStartupTab(String url, int flags) { |
- // We aren't showing about:home, so cancel the telemetry timer |
- if (url != null || mShouldRestore) { |
- mAboutHomeStartupTimer.cancel(); |
- } |
- |
- super.loadStartupTab(url, flags); |
- } |
- |
private void setToolbarMargin(int margin) { |
((RelativeLayout.LayoutParams) mGeckoLayout.getLayoutParams()).topMargin = margin; |
mGeckoLayout.requestLayout(); |
@@ -1322,6 +1520,7 @@ public class BrowserApp extends GeckoApp |
invalidateOptionsMenu(); |
if (mTabsPanel != null) { |
+ mRootLayout.reset(); |
updateSideBarState(); |
mTabsPanel.refresh(); |
} |
@@ -1338,15 +1537,8 @@ public class BrowserApp extends GeckoApp |
return (mTabsPanel != null && mTabsPanel.isSideBar()); |
} |
- private void setBrowserToolbarVisible(final boolean visible) { |
- ThreadUtils.postToUiThread(new Runnable() { |
- @Override |
- public void run() { |
- if (mDynamicToolbar.isEnabled()) { |
- mDynamicToolbar.setVisible(visible, VisibilityTransition.IMMEDIATE); |
- } |
- } |
- }); |
+ private boolean isSideBar() { |
+ return (HardwareUtils.isTablet() && getOrientation() == Configuration.ORIENTATION_LANDSCAPE); |
} |
private void updateSideBarState() { |
@@ -1357,7 +1549,7 @@ public class BrowserApp extends GeckoApp |
if (mMainLayoutAnimator != null) |
mMainLayoutAnimator.stop(); |
- boolean isSideBar = (HardwareUtils.isTablet() && getOrientation() == Configuration.ORIENTATION_LANDSCAPE); |
+ boolean isSideBar = isSideBar(); |
final int sidebarWidth = getResources().getDimensionPixelSize(R.dimen.tabs_sidebar_width); |
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mTabsPanel.getLayoutParams(); |
@@ -1369,6 +1561,7 @@ public class BrowserApp extends GeckoApp |
mMainLayout.scrollTo(mainLayoutScrollX, 0); |
mTabsPanel.setIsSideBar(isSideBar); |
+ mRootLayout.updateDragHelperParameters(); |
} |
@Override |
@@ -1433,6 +1626,10 @@ public class BrowserApp extends GeckoApp |
} |
}); |
+ } else if ("Favicon:CacheLoad".equals(event)) { |
+ final String url = message.getString("url"); |
+ getFaviconFromCache(callback, url); |
+ |
} else if ("Feedback:LastUrl".equals(event)) { |
getLastUrl(callback); |
@@ -1491,31 +1688,71 @@ public class BrowserApp extends GeckoApp |
} |
} else if ("Telemetry:Gather".equals(event)) { |
- Telemetry.addToHistogram("PLACES_PAGES_COUNT", |
- BrowserDB.getCount(getContentResolver(), "history")); |
- Telemetry.addToHistogram("PLACES_BOOKMARKS_COUNT", |
- BrowserDB.getCount(getContentResolver(), "bookmarks")); |
- Telemetry.addToHistogram("FENNEC_FAVICONS_COUNT", |
- BrowserDB.getCount(getContentResolver(), "favicons")); |
- Telemetry.addToHistogram("FENNEC_THUMBNAILS_COUNT", |
- BrowserDB.getCount(getContentResolver(), "thumbnails")); |
- Telemetry.addToHistogram("FENNEC_READING_LIST_COUNT", |
- BrowserDB.getCount(getContentResolver(), "readinglist")); |
+ final BrowserDB db = getProfile().getDB(); |
+ final ContentResolver cr = getContentResolver(); |
+ Telemetry.addToHistogram("PLACES_PAGES_COUNT", db.getCount(cr, "history")); |
+ Telemetry.addToHistogram("PLACES_BOOKMARKS_COUNT", db.getCount(cr, "bookmarks")); |
+ Telemetry.addToHistogram("FENNEC_FAVICONS_COUNT", db.getCount(cr, "favicons")); |
+ Telemetry.addToHistogram("FENNEC_THUMBNAILS_COUNT", db.getCount(cr, "thumbnails")); |
+ Telemetry.addToHistogram("FENNEC_READING_LIST_COUNT", db.getReadingListAccessor().getCount(cr)); |
Telemetry.addToHistogram("BROWSER_IS_USER_DEFAULT", (isDefaultBrowser(Intent.ACTION_VIEW) ? 1 : 0)); |
if (Versions.feature16Plus) { |
Telemetry.addToHistogram("BROWSER_IS_ASSIST_DEFAULT", (isDefaultBrowser(Intent.ACTION_ASSIST) ? 1 : 0)); |
} |
} else if ("Updater:Launch".equals(event)) { |
handleUpdaterLaunch(); |
- |
- } else if ("BrowserToolbar:Visibility".equals(event)) { |
- setBrowserToolbarVisible(message.getBoolean("visible")); |
- |
} else { |
super.handleMessage(event, message, callback); |
} |
} |
+ private void getFaviconFromCache(final EventCallback callback, final String url) { |
+ final OnFaviconLoadedListener listener = new OnFaviconLoadedListener() { |
+ @Override |
+ public void onFaviconLoaded(final String url, final String faviconURL, final Bitmap favicon) { |
+ ThreadUtils.assertOnUiThread(); |
+ // Convert Bitmap to Base64 data URI in background. |
+ ThreadUtils.postToBackgroundThread(new Runnable() { |
+ @Override |
+ public void run() { |
+ ByteArrayOutputStream out = null; |
+ Base64OutputStream b64 = null; |
+ |
+ // Failed to load favicon from local. |
+ if (favicon == null) { |
+ callback.sendError("Failed to get favicon from cache"); |
+ } else { |
+ try { |
+ out = new ByteArrayOutputStream(); |
+ out.write("data:image/png;base64,".getBytes()); |
+ b64 = new Base64OutputStream(out, Base64.NO_WRAP); |
+ favicon.compress(Bitmap.CompressFormat.PNG, 100, b64); |
+ callback.sendSuccess(new String(out.toByteArray())); |
+ } catch (IOException e) { |
+ Log.w(LOGTAG, "Failed to convert to base64 data URI"); |
+ callback.sendError("Failed to convert favicon to a base64 data URI"); |
+ } finally { |
+ try { |
+ if (out != null) { |
+ out.close(); |
+ } |
+ if (b64 != null) { |
+ b64.close(); |
+ } |
+ } catch (IOException e) { |
+ Log.w(LOGTAG, "Failed to close the streams"); |
+ } |
+ } |
+ } |
+ } |
+ }); |
+ } |
+ }; |
+ Favicons.getSizedFaviconForPageFromLocal(getContext(), |
+ url, |
+ listener); |
+ } |
+ |
/** |
* Use a dummy Intent to do a default browser check. |
* |
@@ -1703,11 +1940,14 @@ public class BrowserApp extends GeckoApp |
@Override |
public void onGlobalLayout() { |
mTabsPanel.getViewTreeObserver().removeGlobalOnLayoutListener(this); |
- mTabsPanel.show(panel); |
+ showTabs(panel); |
} |
}); |
} |
} else { |
+ if (mDoorHangerPopup != null) { |
+ mDoorHangerPopup.disable(); |
+ } |
mTabsPanel.show(panel); |
} |
} |
@@ -1715,6 +1955,9 @@ public class BrowserApp extends GeckoApp |
@Override |
public void hideTabs() { |
mTabsPanel.hide(); |
+ if (mDoorHangerPopup != null) { |
+ mDoorHangerPopup.enable(); |
+ } |
} |
@Override |
@@ -1792,10 +2035,13 @@ public class BrowserApp extends GeckoApp |
if (!areTabsShown()) { |
mTabsPanel.setVisibility(View.INVISIBLE); |
mTabsPanel.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); |
+ mRootLayout.setClosed(); |
+ mBrowserToolbar.setContextMenuEnabled(true); |
} else { |
// Cancel editing mode to return to page content when the TabsPanel closes. We cancel |
// it here because there are graphical glitches if it's canceled while it's visible. |
mBrowserToolbar.cancelEdit(); |
+ mRootLayout.setOpen(); |
} |
mTabsPanel.finishTabsAnimation(); |
@@ -1905,12 +2151,21 @@ public class BrowserApp extends GeckoApp |
&& mHomePagerContainer != null && mHomePagerContainer.getVisibility() == View.VISIBLE); |
} |
+ private boolean isFirstrunVisible() { |
+ return (mFirstrunPane != null && mFirstrunPane.isVisible() |
+ && mHomePagerContainer != null && mHomePagerContainer.getVisibility() == View.VISIBLE); |
+ } |
+ |
/** |
* Enters editing mode with the current tab's URL. There might be no |
* tabs loaded by the time the user enters editing mode e.g. just after |
* the app starts. In this case, we simply fallback to an empty URL. |
*/ |
private void enterEditingMode() { |
+ if (hideFirstrunPager()) { |
+ Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL, TelemetryContract.Method.ACTIONBAR, "firstrun-pane"); |
+ } |
+ |
String url = ""; |
final Tab tab = Tabs.getInstance().getSelectedTab(); |
@@ -1939,7 +2194,14 @@ public class BrowserApp extends GeckoApp |
} |
final Tab selectedTab = Tabs.getInstance().getSelectedTab(); |
- mTargetTabForEditingMode = (selectedTab != null ? selectedTab.getId() : null); |
+ final String panelId; |
+ if (selectedTab != null) { |
+ mTargetTabForEditingMode = selectedTab.getId(); |
+ panelId = selectedTab.getMostRecentHomePanel(); |
+ } else { |
+ mTargetTabForEditingMode = null; |
+ panelId = null; |
+ } |
final PropertyAnimator animator = new PropertyAnimator(250); |
animator.setUseHardwareLayer(false); |
@@ -1948,7 +2210,6 @@ public class BrowserApp extends GeckoApp |
mBrowserToolbar.startEditing(url, animator); |
- final String panelId = selectedTab.getMostRecentHomePanel(); |
showHomePagerWithAnimator(panelId, animator); |
animator.start(); |
@@ -1994,6 +2255,7 @@ public class BrowserApp extends GeckoApp |
} |
// Otherwise, check for a bookmark keyword. |
+ final BrowserDB db = getProfile().getDB(); |
ThreadUtils.postToBackgroundThread(new Runnable() { |
@Override |
public void run() { |
@@ -2009,7 +2271,7 @@ public class BrowserApp extends GeckoApp |
keywordSearch = url.substring(index + 1); |
} |
- final String keywordUrl = BrowserDB.getUrlForKeyword(getContentResolver(), keyword); |
+ final String keywordUrl = db.getUrlForKeyword(getContentResolver(), keyword); |
// If there isn't a bookmark keyword, load the url. This may result in a query |
// using the default search engine. |
@@ -2022,7 +2284,11 @@ public class BrowserApp extends GeckoApp |
recordSearch(null, "barkeyword"); |
// Otherwise, construct a search query from the bookmark keyword. |
- final String searchUrl = keywordUrl.replace("%s", URLEncoder.encode(keywordSearch)); |
+ // 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, |
@@ -2059,17 +2325,22 @@ public class BrowserApp extends GeckoApp |
* @param query |
* a search query to store. We won't store empty queries. |
*/ |
- private void storeSearchQuery(String query) { |
+ private void storeSearchQuery(final String query) { |
if (TextUtils.isEmpty(query)) { |
return; |
} |
- final ContentValues values = new ContentValues(); |
- values.put(SearchHistory.QUERY, query); |
+ final GeckoProfile profile = getProfile(); |
+ // Don't bother storing search queries in guest mode |
+ if (profile.inGuestMode()) { |
+ return; |
+ } |
+ |
+ final BrowserDB db = profile.getDB(); |
ThreadUtils.postToBackgroundThread(new Runnable() { |
@Override |
public void run() { |
- getContentResolver().insert(SearchHistory.CONTENT_URI, values); |
+ db.getSearches().insert(getContentResolver(), query); |
} |
}); |
} |
@@ -2096,7 +2367,7 @@ public class BrowserApp extends GeckoApp |
* temporarily selected tab is visible to users. |
*/ |
private void selectTargetTabForEditingMode() { |
- if (NewTabletUI.isEnabled(this)) { |
+ if (HardwareUtils.isTablet()) { |
return; |
} |
@@ -2177,6 +2448,22 @@ public class BrowserApp extends GeckoApp |
} |
} |
+ private void showFirstrunPager() { |
Felix Dahlke
2015/07/22 16:19:18
Also more for the record, there's a change for re-
|
+ if (mFirstrunPane == null) { |
+ final ViewStub firstrunPagerStub = (ViewStub) findViewById(R.id.firstrun_pager_stub); |
+ mFirstrunPane = (FirstrunPane) firstrunPagerStub.inflate(); |
+ mFirstrunPane.load(getSupportFragmentManager()); |
+ mFirstrunPane.registerOnFinishListener(new FirstrunPane.OnFinishListener() { |
+ @Override |
+ public void onFinish() { |
+ BrowserApp.this.mFirstrunPane = null; |
+ } |
+ }); |
+ } |
+ |
+ mHomePagerContainer.setVisibility(View.VISIBLE); |
+ } |
+ |
private void showHomePager(String panelId) { |
showHomePagerWithAnimator(panelId, null); |
} |
@@ -2264,6 +2551,15 @@ public class BrowserApp extends GeckoApp |
mLayerView.setVisibility(View.INVISIBLE); |
} |
+ public boolean hideFirstrunPager() { |
+ if (!isFirstrunVisible()) { |
+ return false; |
+ } |
+ |
+ mFirstrunPane.hide(); |
+ return true; |
+ } |
+ |
/** |
* Hides the HomePager, using the url of the currently selected tab as the url to be |
* loaded. |
@@ -2585,8 +2881,12 @@ public class BrowserApp extends GeckoApp |
// Action providers are available only ICS+. |
if (Versions.feature14Plus) { |
GeckoMenuItem share = (GeckoMenuItem) mMenu.findItem(R.id.share); |
+ final GeckoMenuItem quickShare = (GeckoMenuItem) mMenu.findItem(R.id.quickshare); |
+ |
GeckoActionProvider provider = GeckoActionProvider.getForType(GeckoActionProvider.DEFAULT_MIME_TYPE, this); |
+ |
share.setActionProvider(provider); |
+ quickShare.setActionProvider(provider); |
} |
org.adblockplus.browser.BrowserAppUtils.updateBlockAdsMenuItem( |
@@ -2599,7 +2899,7 @@ public class BrowserApp extends GeckoApp |
public void openOptionsMenu() { |
// Disable menu access (for hardware buttons) when the software menu button is inaccessible. |
// Note that the software button is always accessible on new tablet. |
- if (mBrowserToolbar.isEditing() && !NewTabletUI.isEnabled(this)) { |
+ if (mBrowserToolbar.isEditing() && !HardwareUtils.isTablet()) { |
return; |
} |
@@ -2673,9 +2973,11 @@ public class BrowserApp extends GeckoApp |
Tab tab = Tabs.getInstance().getSelectedTab(); |
MenuItem bookmark = aMenu.findItem(R.id.bookmark); |
+ final MenuItem reader = aMenu.findItem(R.id.reading_list); |
MenuItem back = aMenu.findItem(R.id.back); |
MenuItem forward = aMenu.findItem(R.id.forward); |
MenuItem share = aMenu.findItem(R.id.share); |
+ final MenuItem quickShare = aMenu.findItem(R.id.quickshare); |
MenuItem saveAsPDF = aMenu.findItem(R.id.save_as_pdf); |
MenuItem charEncoding = aMenu.findItem(R.id.char_encoding); |
MenuItem findInPage = aMenu.findItem(R.id.find_in_page); |
@@ -2693,12 +2995,15 @@ public class BrowserApp extends GeckoApp |
ClearOnShutdownPref.PREF, |
new HashSet<String>()).isEmpty(); |
aMenu.findItem(R.id.quit).setVisible(visible); |
+ aMenu.findItem(R.id.logins).setVisible(AppConstants.NIGHTLY_BUILD); |
if (tab == null || tab.getURL() == null) { |
bookmark.setEnabled(false); |
+ reader.setEnabled(false); |
back.setEnabled(false); |
forward.setEnabled(false); |
share.setEnabled(false); |
+ quickShare.setEnabled(false); |
saveAsPDF.setEnabled(false); |
findInPage.setEnabled(false); |
@@ -2716,11 +3021,23 @@ public class BrowserApp extends GeckoApp |
return true; |
} |
- bookmark.setEnabled(!AboutPages.isAboutReader(tab.getURL())); |
- bookmark.setVisible(!GeckoProfile.get(this).inGuestMode()); |
+ final boolean inGuestMode = GeckoProfile.get(this).inGuestMode(); |
+ |
+ final boolean isAboutReader = AboutPages.isAboutReader(tab.getURL()); |
+ bookmark.setEnabled(!isAboutReader); |
+ bookmark.setVisible(!inGuestMode); |
bookmark.setCheckable(true); |
bookmark.setChecked(tab.isBookmark()); |
bookmark.setIcon(resolveBookmarkIconID(tab.isBookmark())); |
+ bookmark.setTitle(resolveBookmarkTitleID(tab.isBookmark())); |
+ |
+ reader.setEnabled(isAboutReader || !AboutPages.isAboutPage(tab.getURL())); |
+ reader.setVisible(!inGuestMode); |
+ reader.setCheckable(true); |
+ final boolean isPageInReadingList = tab.isInReadingList(); |
+ reader.setChecked(isPageInReadingList); |
+ reader.setIcon(resolveReadingListIconID(isPageInReadingList)); |
+ reader.setTitle(resolveReadingListTitleID(isPageInReadingList)); |
back.setEnabled(tab.canDoBack()); |
forward.setEnabled(tab.canDoForward()); |
@@ -2736,9 +3053,10 @@ public class BrowserApp extends GeckoApp |
} |
// Disable share menuitem for about:, chrome:, file:, and resource: URIs |
- final boolean shareEnabled = RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_SHARE); |
- share.setVisible(shareEnabled); |
- share.setEnabled(StringUtils.isShareableUrl(url) && shareEnabled); |
+ final boolean shareVisible = RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_SHARE); |
+ share.setVisible(shareVisible); |
+ final boolean shareEnabled = StringUtils.isShareableUrl(url) && shareVisible; |
+ share.setEnabled(shareEnabled); |
MenuUtils.safeSetEnabled(aMenu, R.id.apps, RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_INSTALL_APPS)); |
MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_INSTALL_EXTENSION)); |
MenuUtils.safeSetEnabled(aMenu, R.id.downloads, RestrictedProfiles.isAllowed(this, RestrictedProfiles.Restriction.DISALLOW_DOWNLOADS)); |
@@ -2755,6 +3073,10 @@ public class BrowserApp extends GeckoApp |
// Action providers are available only ICS+. |
if (Versions.feature14Plus) { |
+ quickShare.setVisible(shareVisible); |
+ quickShare.setEnabled(shareEnabled); |
+ |
+ // This provider also applies to the quick share menu item. |
final GeckoActionProvider provider = ((GeckoMenuItem) share).getGeckoActionProvider(); |
if (provider != null) { |
Intent shareIntent = provider.getIntent(); |
@@ -2770,6 +3092,7 @@ public class BrowserApp extends GeckoApp |
shareIntent.putExtra(Intent.EXTRA_TEXT, url); |
shareIntent.putExtra(Intent.EXTRA_SUBJECT, tab.getDisplayTitle()); |
shareIntent.putExtra(Intent.EXTRA_TITLE, tab.getDisplayTitle()); |
+ shareIntent.putExtra(ShareDialog.INTENT_EXTRA_DEVICES_ONLY, true); |
// Clear the existing thumbnail extras so we don't share an old thumbnail. |
shareIntent.removeExtra("share_screenshot_uri"); |
@@ -2835,6 +3158,18 @@ public class BrowserApp extends GeckoApp |
} |
} |
+ private int resolveBookmarkTitleID(final boolean isBookmark) { |
+ return (isBookmark ? R.string.bookmark_remove : R.string.bookmark); |
+ } |
+ |
+ private int resolveReadingListIconID(final boolean isInReadingList) { |
+ return (isInReadingList ? R.drawable.ic_menu_reader_remove : R.drawable.ic_menu_reader_add); |
+ } |
+ |
+ private int resolveReadingListTitleID(final boolean isInReadingList) { |
+ return (isInReadingList ? R.string.reading_list_remove : R.string.overlay_share_reading_list_btn_label); |
+ } |
+ |
@Override |
public boolean onOptionsItemSelected(MenuItem item) { |
Tab tab = null; |
@@ -2857,10 +3192,30 @@ public class BrowserApp extends GeckoApp |
Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.MENU, "bookmark"); |
tab.removeBookmark(); |
item.setIcon(resolveBookmarkIconID(false)); |
+ item.setTitle(resolveBookmarkTitleID(false)); |
} else { |
Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.MENU, "bookmark"); |
tab.addBookmark(); |
item.setIcon(resolveBookmarkIconID(true)); |
+ item.setTitle(resolveBookmarkTitleID(true)); |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ if (itemId == R.id.reading_list) { |
+ tab = Tabs.getInstance().getSelectedTab(); |
+ if (tab != null) { |
+ if (item.isChecked()) { |
+ Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.MENU, "reading_list"); |
+ tab.removeFromReadingList(); |
+ item.setIcon(resolveReadingListIconID(false)); |
+ item.setTitle(resolveReadingListTitleID(false)); |
+ } else { |
+ Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.MENU, "reading_list"); |
+ tab.addToReadingList(); |
+ item.setIcon(resolveReadingListIconID(true)); |
+ item.setTitle(resolveReadingListTitleID(true)); |
} |
} |
return true; |
@@ -2921,6 +3276,11 @@ public class BrowserApp extends GeckoApp |
return true; |
} |
+ if (itemId == R.id.logins) { |
+ Tabs.getInstance().loadUrlInTab(AboutPages.PASSWORDS); |
+ return true; |
+ } |
+ |
if (itemId == R.id.apps) { |
Tabs.getInstance().loadUrlInTab(AboutPages.APPS); |
return true; |
@@ -3066,11 +3426,15 @@ public class BrowserApp extends GeckoApp |
final boolean isViewAction = Intent.ACTION_VIEW.equals(action); |
final boolean isBookmarkAction = GeckoApp.ACTION_HOMESCREEN_SHORTCUT.equals(action); |
+ final boolean isTabQueueAction = TabQueueHelper.LOAD_URLS_ACTION.equals(action); |
if (mInitialized && (isViewAction || isBookmarkAction)) { |
// Dismiss editing mode if the user is loading a URL from an external app. |
mBrowserToolbar.cancelEdit(); |
+ // Hide firstrun-pane if the user is loading a URL from an external app. |
+ hideFirstrunPager(); |
+ |
// GeckoApp.ACTION_HOMESCREEN_SHORTCUT means we're opening a bookmark that |
// was added to Android's homescreen. |
final TelemetryContract.Method method = |
@@ -3091,6 +3455,17 @@ public class BrowserApp extends GeckoApp |
GuestSession.handleIntent(this, intent); |
} |
+ // If the user has clicked the tab queue notification then load the tabs. |
+ if(AppConstants.NIGHTLY_BUILD && AppConstants.MOZ_ANDROID_TAB_QUEUE && mInitialized && isTabQueueAction) { |
+ int queuedTabCount = TabQueueHelper.getTabQueueLength(this); |
+ TabQueueHelper.openQueuedUrls(this, mProfile, TabQueueHelper.FILE_NAME); |
+ |
+ // If there's more than one tab then also show the tabs panel. |
+ if (queuedTabCount > 1) { |
+ showNormalTabs(); |
+ } |
+ } |
+ |
if (!mInitialized || !Intent.ACTION_MAIN.equals(action)) { |
return; |
} |
@@ -3131,22 +3506,23 @@ public class BrowserApp extends GeckoApp |
} |
private void getLastUrl(final EventCallback callback) { |
+ final BrowserDB db = getProfile().getDB(); |
(new UIAsyncTask.WithoutParams<String>(ThreadUtils.getBackgroundHandler()) { |
@Override |
public synchronized String doInBackground() { |
// Get the most recent URL stored in browser history. |
- String url = ""; |
- Cursor c = null; |
+ final Cursor c = db.getRecentHistory(getContentResolver(), 1); |
+ if (c == null) { |
+ return ""; |
+ } |
try { |
- c = BrowserDB.getRecentHistory(getContentResolver(), 1); |
if (c.moveToFirst()) { |
- url = c.getString(c.getColumnIndexOrThrow(Combined.URL)); |
+ return c.getString(c.getColumnIndexOrThrow(Combined.URL)); |
} |
+ return ""; |
} finally { |
- if (c != null) |
- c.close(); |
+ c.close(); |
} |
- return url; |
} |
@Override |
@@ -3242,6 +3618,12 @@ public class BrowserApp extends GeckoApp |
return GeckoProfile.getDefaultProfileName(this); |
} |
+ // For use from tests only. |
+ @RobocopTarget |
+ public ReadingListHelper getReadingListHelper() { |
+ return mReadingListHelper; |
+ } |
+ |
/** |
* Launch UI that lets the user update Firefox. |
* |