From 790b6fa10013479f5cdafc1185d0a6a745dfde73 Mon Sep 17 00:00:00 2001 From: Nevin Chen Date: Thu, 29 Dec 2016 14:22:45 +0800 Subject: [PATCH] Bug 1275662 - Close all tabs and clean up session files when "Open Tabs" is selected in "Clear private data on exit" or "Clear private data" pref. r=JanH,sebastian MozReview-Commit-ID: GoUQVDIzYbI --HG-- extra : rebase_source : 13bbf3477a29cf301df72b521a0e02875bb5ef14 --- .../java/org/mozilla/gecko/BrowserApp.java | 7 +++++++ .../base/java/org/mozilla/gecko/GeckoApp.java | 17 +++++++++------- .../base/java/org/mozilla/gecko/Tabs.java | 6 ++++++ .../org/mozilla/gecko/home/HomePager.java | 9 +++++++-- mobile/android/chrome/content/browser.js | 6 ++++++ mobile/android/components/SessionStore.js | 10 +++++++++- mobile/android/modules/Sanitizer.jsm | 20 +++++++++++++++++++ 7 files changed, 65 insertions(+), 10 deletions(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java index 133bf3b18c2e3..87a3d0a95fa2c 100644 --- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java @@ -741,6 +741,7 @@ public boolean onInterceptMotionEvent(View view, MotionEvent event) { "CharEncoding:State", "Settings:Show", "Updater:Launch", + "Sanitize:OpenTabs", null); EventDispatcher.getInstance().registerBackgroundThreadListener(this, @@ -1454,6 +1455,7 @@ public void onDestroy() { "CharEncoding:State", "Settings:Show", "Updater:Launch", + "Sanitize:OpenTabs", null); EventDispatcher.getInstance().unregisterBackgroundThreadListener(this, @@ -1914,6 +1916,11 @@ public void onClick(final DialogInterface dialog, final int which) { settings.edit().putInt(getPackageName() + ".feedback_launch_count", 0).apply(); break; + case "Sanitize:OpenTabs": + Tabs.getInstance().closeAll(); + callback.sendSuccess(null); + break; + case "Sanitize:ClearHistory": BrowserDB.from(getProfile()).clearHistory( getContentResolver(), message.getBoolean("clearSearchHistory", false)); diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java index cfeb20de16097..4c9ff063c2160 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -585,17 +585,20 @@ public boolean onOptionsItemSelected(MenuItem item) { Log.e(LOGTAG, "Error adding sanitize object", ex); } - // If the user has opted out of session restore, and does want to clear history + // If the user wants to clear open tabs, or else has opted out of session restore and does want to clear history, // we also want to prevent the current session info from being saved. - if (clearObj.has("private.data.history")) { - final String sessionRestore = getSessionRestorePreference(getSharedPreferences()); - try { + try { + if (clearObj.has("private.data.openTabs")) { + res.put("dontSaveSession", true); + } else if (clearObj.has("private.data.history")) { + + final String sessionRestore = getSessionRestorePreference(getSharedPreferences()); res.put("dontSaveSession", "quit".equals(sessionRestore)); - } catch (JSONException ex) { - Log.e(LOGTAG, "Error adding session restore data", ex); + } + } catch (JSONException ex) { + Log.e(LOGTAG, "Error adding session restore data", ex); } - GeckoAppShell.notifyObservers("Browser:Quit", res.toString()); // We don't call doShutdown() here because this creates a race condition which can // cause the clearing of private data to fail. Instead, we shut down the UI only after diff --git a/mobile/android/base/java/org/mozilla/gecko/Tabs.java b/mobile/android/base/java/org/mozilla/gecko/Tabs.java index 8000c3c5b80b5..6021877dd55d7 100644 --- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java +++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java @@ -85,6 +85,12 @@ public class Tabs implements BundleEventListener { private PersistTabsRunnable mPersistTabsRunnable; private int mPrivateClearColor; + public void closeAll() { + for (final Tab tab : mOrder) { + Tabs.getInstance().closeTab(tab, false); + } + } + private static class PersistTabsRunnable implements Runnable { private final BrowserDB db; private final Context context; diff --git a/mobile/android/base/java/org/mozilla/gecko/home/HomePager.java b/mobile/android/base/java/org/mozilla/gecko/home/HomePager.java index 4915f0c919fc3..4811c4c1d4964 100644 --- a/mobile/android/base/java/org/mozilla/gecko/home/HomePager.java +++ b/mobile/android/base/java/org/mozilla/gecko/home/HomePager.java @@ -225,8 +225,13 @@ public void load(LoaderManager lm, FragmentManager fm, String panelId, Bundle re // list of panels in place. mTabStrip.setVisibility(View.INVISIBLE); - // Load list of panels from configuration - lm.initLoader(LOADER_ID_CONFIG, null, mConfigLoaderCallbacks); + // If HomeConfigLoader already exist, force load to select the current item + if (lm.getLoader(LOADER_ID_CONFIG) != null) { + lm.getLoader(LOADER_ID_CONFIG).forceLoad(); + } else { + // Load list of panels from configuration + lm.initLoader(LOADER_ID_CONFIG, null, mConfigLoaderCallbacks); + } if (shouldAnimate) { animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() { diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 6e886ae336a19..e2432e5919f10 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1470,6 +1470,12 @@ var BrowserApp = { promises.push(Sanitizer.clearItem("cookies")); promises.push(Sanitizer.clearItem("sessions")); break; + case "openTabs": + if (aShutdown === true) { + Services.obs.notifyObservers(null, "browser:purge-session-tabs", ""); + break; + } + // fall-through if aShutdown is false default: promises.push(Sanitizer.clearItem(key)); } diff --git a/mobile/android/components/SessionStore.js b/mobile/android/components/SessionStore.js index 9f75d6acfad38..43adaefb708e0 100644 --- a/mobile/android/components/SessionStore.js +++ b/mobile/android/components/SessionStore.js @@ -180,6 +180,7 @@ SessionStore.prototype = { observerService.addObserver(this, "domwindowopened", true); observerService.addObserver(this, "domwindowclosed", true); observerService.addObserver(this, "browser:purge-session-history", true); + observerService.addObserver(this, "browser:purge-session-tabs", true); observerService.addObserver(this, "quit-application-requested", true); observerService.addObserver(this, "quit-application-proceeding", true); observerService.addObserver(this, "quit-application", true); @@ -236,8 +237,9 @@ SessionStore.prototype = { this._loadState = STATE_QUITTING_FLUSHED; break; + case "browser:purge-session-tabs": case "browser:purge-session-history": // catch sanitization - log("browser:purge-session-history"); + log(aTopic); this._clearDisk(); // Clear all data about closed tabs @@ -1780,6 +1782,12 @@ SessionStore.prototype = { }, _sendClosedTabsToJava: function ss_sendClosedTabsToJava(aWindow) { + + // If the app is shutting down, we don't need to do anything. + if (this._loadState <= STATE_QUITTING) { + return; + } + if (!aWindow.__SSID) { throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); } diff --git a/mobile/android/modules/Sanitizer.jsm b/mobile/android/modules/Sanitizer.jsm index 126707754db39..a06c5fbf31157 100644 --- a/mobile/android/modules/Sanitizer.jsm +++ b/mobile/android/modules/Sanitizer.jsm @@ -168,6 +168,26 @@ Sanitizer.prototype = { } }, + openTabs: { + clear: function () + { + return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:OpenTabs" }) + .catch(e => Cu.reportError("Java-side tab clearing failed: " + e)) + .then(function() { + try { + // clear "Recently Closed" tabs in Android App + Services.obs.notifyObservers(null, "browser:purge-session-tabs", ""); + } + catch (e) { } + }); + }, + + get canClear() + { + return true; + } + }, + searchHistory: { clear: function () {