Bug 1352997 - Part 7 - Don't switch activities if we're closing a tab while exiting the activity. r?sebastian,walkingice draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Fri, 14 Apr 2017 19:58:09 +0200
changeset 569645 0de317bc41cf2e8c9e310dd82798e128c9472a7f
parent 569644 eec886a795e5cfc4c526dd77ec8ae9ef6bc0f5b7
child 569646 c04c3d99f68d1edc339f6b1dd8d1cc69a873fcc1
push id56240
push usermozilla@buttercookie.de
push dateThu, 27 Apr 2017 18:44:39 +0000
reviewerssebastian, walkingice
bugs1352997
milestone55.0a1
Bug 1352997 - Part 7 - Don't switch activities if we're closing a tab while exiting the activity. r?sebastian,walkingice Closing the currently selected tab will select another tab, which can trigger an activity switch if the tab types differ. We don't want that if we're about to close the activity, as that'll bring that activity into the foreground instead of simply walking back along the activity history stack. To give an example: Without this patch, closing the last custom tab will select a normal browsing tab, which will trigger an activity switch, so instead of returning to the user's previous activity, pressing back will send us to BrowserApp. There's one additional catch: If we change our onDone() behaviour and no longer finish() the SingleTabActivity when exiting (in order to avoid a costly restart of Gecko should the user return to us soon), this means that the activity that has just been exited could be brought back into the foreground via the onResume() codepath. In that case the mLastActiveGeckoApp-check won't be triggered if no other GeckoApp-based activity was active in the meantime, so we wouldn't reselect/reopen the activity's desired tab, but instead display the tab that was selected when closing the previous tab. Therefore, we track this via an additional flag that is set for this case. MozReview-Commit-ID: 3jOvBXQUrfo
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/Tabs.java
mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -217,16 +217,17 @@ public abstract class GeckoApp
     private final HashMap<String, PowerManager.WakeLock> mWakeLocks = new HashMap<String, PowerManager.WakeLock>();
 
     protected boolean mLastSessionCrashed;
     protected boolean mShouldRestore;
     private boolean mSessionRestoreParsingFinished = false;
 
     protected int mLastSelectedTabId = INVALID_TAB_ID;
     protected String mLastSessionUUID = null;
+    protected boolean mCheckTabSelectionOnResume = false;
 
     private boolean foregrounded = false;
 
     private static final class LastSessionParser extends SessionParser {
         private JSONArray tabs;
         private JSONObject windowObject;
         private boolean isExternalURL;
 
@@ -2398,17 +2399,19 @@ public abstract class GeckoApp
             return;
         }
 
         foregrounded = true;
 
         GeckoAppShell.setGeckoInterface(this);
         GeckoAppShell.setScreenOrientationDelegate(this);
 
-        if (mLastActiveGeckoApp == null || mLastActiveGeckoApp.get() != this) {
+        if (mLastActiveGeckoApp == null || mLastActiveGeckoApp.get() != this ||
+                mCheckTabSelectionOnResume) {
+            mCheckTabSelectionOnResume = false;
             restoreLastSelectedTab();
         }
 
         int newOrientation = getResources().getConfiguration().orientation;
         if (GeckoScreenOrientation.getInstance().update(newOrientation)) {
             refreshChrome();
         }
 
@@ -2849,17 +2852,18 @@ public abstract class GeckoApp
                     Tab nextSelectedTab = Tabs.getInstance().getNextTab(tab);
                     // Closing the tab will select the next tab. There's no need to unzombify it
                     // if we're really exiting - switching activities is a different matter, though.
                     if (nextSelectedTab != null && nextSelectedTab.getType() == tab.getType()) {
                         final GeckoBundle data = new GeckoBundle(1);
                         data.putInt("nextSelectedTabId", nextSelectedTab.getId());
                         EventDispatcher.getInstance().dispatch("Tab:KeepZombified", data);
                     }
-                    tabs.closeTab(tab);
+                    tabs.closeTabNoActivitySwitch(tab);
+                    mCheckTabSelectionOnResume = true;
                     return;
                 }
 
                 final int parentId = tab.getParentId();
                 final Tab parent = tabs.getTab(parentId);
                 if (parent != null) {
                     // The back button should always return to the parent (not a sibling).
                     tabs.closeTab(tab, parent);
--- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java
@@ -308,29 +308,33 @@ public class Tabs implements BundleEvent
             Tab tab = getTab(id);
             mOrder.remove(tab);
             mTabs.remove(id);
             tabPositionCache.mTabId = INVALID_TAB_ID;
         }
     }
 
     public synchronized Tab selectTab(int id) {
+        return selectTab(id, true);
+    }
+
+    public synchronized Tab selectTab(int id, boolean switchActivities) {
         if (!mTabs.containsKey(id))
             return null;
 
         final Tab oldTab = getSelectedTab();
         final Tab tab = mTabs.get(id);
 
         // This avoids a NPE below, but callers need to be careful to
         // handle this case.
         if (tab == null || oldTab == tab) {
             return tab;
         }
 
-        if (oldTab != null && oldTab.getType() != tab.getType() &&
+        if (switchActivities && oldTab != null && oldTab.getType() != tab.getType() &&
                 !currentActivityMatchesTab(tab)) {
             // We're in the wrong activity for this kind of tab, so launch the correct one
             // and then try again.
             launchActivityForTab(tab);
             return tab;
         }
 
         mSelectedTab = tab;
@@ -531,37 +535,43 @@ public class Tabs implements BundleEvent
     }
 
     /** Close tab and then select the default next tab */
     @RobocopTarget
     public synchronized void closeTab(Tab tab) {
         closeTab(tab, getNextTab(tab));
     }
 
+    /** Don't switch activities even if the default next tab is of a different tab type */
+    public synchronized void closeTabNoActivitySwitch(Tab tab) {
+        closeTab(tab, getNextTab(tab), false, false);
+    }
+
     public synchronized void closeTab(Tab tab, Tab nextTab) {
-        closeTab(tab, nextTab, false);
+        closeTab(tab, nextTab, false, true);
     }
 
     public synchronized void closeTab(Tab tab, boolean showUndoToast) {
-        closeTab(tab, getNextTab(tab), showUndoToast);
+        closeTab(tab, getNextTab(tab), showUndoToast, true);
     }
 
     /** Close tab and then select nextTab */
-    public synchronized void closeTab(final Tab tab, Tab nextTab, boolean showUndoToast) {
+    public synchronized void closeTab(final Tab tab, Tab nextTab,
+                                      boolean showUndoToast, boolean switchActivities) {
         if (tab == null)
             return;
 
         int tabId = tab.getId();
         removeTab(tabId);
 
         if (nextTab == null) {
             nextTab = loadUrl(getHomepageForNewTab(mAppContext), LOADURL_NEW_TAB);
         }
 
-        selectTab(nextTab.getId());
+        selectTab(nextTab.getId(), switchActivities);
 
         tab.onDestroy();
 
         // Pass a message to Gecko to update tab state in BrowserApp
         final GeckoBundle data = new GeckoBundle(2);
         data.putInt("tabId", tabId);
         data.putBoolean("showUndoToast", showUndoToast);
         EventDispatcher.getInstance().dispatch("Tab:Closed", data);
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -343,17 +343,18 @@ public class CustomTabsActivity extends 
 
     private void bindNavigationCallback(@NonNull final Toolbar toolbar) {
         toolbar.setNavigationOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 onDone();
                 final Tabs tabs = Tabs.getInstance();
                 final Tab tab = tabs.getSelectedTab();
-                tabs.closeTab(tab);
+                tabs.closeTabNoActivitySwitch(tab);
+                mCheckTabSelectionOnResume = true;
             }
         });
     }
 
     private void performPendingIntent(@NonNull PendingIntent pendingIntent) {
         // bug 1337771: If intent-creator haven't set data url, call send() directly won't work.
         final Intent additional = new Intent();
         final Tab tab = Tabs.getInstance().getSelectedTab();