Add-an-always-incognito-mode.patch 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. From: Ryan Archer <ryan.bradley.archer@gmail.com>
  2. Date: Wed, 2 Aug 2017 01:41:28 -0400
  3. Subject: Add an always-incognito mode
  4. More specifically, add a preference that causes all new tabs and all
  5. clicked links to launch as incognito.
  6. Make sure initial incognito status is correctly recognized.
  7. Enable incognito custom tabs and fix crashes for incognito/custom tab intents (credits to @uazo)
  8. ---
  9. chrome/android/chrome_java_sources.gni | 1 +
  10. .../java/res/xml/privacy_preferences.xml | 5 ++
  11. .../AlwaysIncognitoLinkInterceptor.java | 80 +++++++++++++++++++
  12. .../chrome/browser/ChromeTabbedActivity.java | 6 +-
  13. .../chrome/browser/app/ChromeActivity.java | 4 +
  14. .../AppMenuPropertiesDelegateImpl.java | 6 ++
  15. .../ChromeContextMenuPopulator.java | 8 +-
  16. .../CustomTabActivityLifecycleUmaTracker.java | 25 ------
  17. .../CustomTabIntentDataProvider.java | 5 +-
  18. .../browser/init/StartupTabPreloader.java | 14 +++-
  19. .../privacy/settings/PrivacySettings.java | 37 ++++++++-
  20. .../browser/settings/SettingsActivity.java | 4 +
  21. .../browser/tabmodel/ChromeTabCreator.java | 16 +++-
  22. .../browser/tabmodel/TabPersistentStore.java | 10 +++
  23. .../webapps/WebappIntentDataProvider.java | 14 ++++
  24. .../flags/android/chrome_feature_list.cc | 2 +-
  25. .../strings/android_chrome_strings.grd | 13 +++
  26. chrome/browser/ui/messages/android/BUILD.gn | 1 +
  27. .../snackbar/INeedSnackbarManager.java | 27 +++++++
  28. 19 files changed, 243 insertions(+), 35 deletions(-)
  29. create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/AlwaysIncognitoLinkInterceptor.java
  30. create mode 100644 chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/INeedSnackbarManager.java
  31. diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
  32. --- a/chrome/android/chrome_java_sources.gni
  33. +++ b/chrome/android/chrome_java_sources.gni
  34. @@ -3,6 +3,7 @@
  35. # found in the LICENSE file.
  36. chrome_java_sources = [
  37. + "java/src/org/chromium/chrome/browser/AlwaysIncognitoLinkInterceptor.java",
  38. "java/src/com/google/android/apps/chrome/appwidget/bookmarks/BookmarkThumbnailWidgetProvider.java",
  39. "java/src/org/chromium/chrome/browser/ActivityTabProvider.java",
  40. "java/src/org/chromium/chrome/browser/ActivityUtils.java",
  41. diff --git a/chrome/android/java/res/xml/privacy_preferences.xml b/chrome/android/java/res/xml/privacy_preferences.xml
  42. --- a/chrome/android/java/res/xml/privacy_preferences.xml
  43. +++ b/chrome/android/java/res/xml/privacy_preferences.xml
  44. @@ -32,6 +32,11 @@
  45. android:key="secure_dns"
  46. android:title="@string/settings_secure_dns_title"
  47. android:fragment="org.chromium.chrome.browser.privacy.secure_dns.SecureDnsSettings"/>
  48. + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
  49. + android:key="always_incognito"
  50. + android:title="@string/always_incognito_title"
  51. + android:summary="@string/always_incognito_summary"
  52. + android:defaultValue="false" />
  53. <Preference
  54. android:fragment="org.chromium.chrome.browser.privacy.settings.DoNotTrackSettings"
  55. android:key="do_not_track"
  56. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AlwaysIncognitoLinkInterceptor.java b/chrome/android/java/src/org/chromium/chrome/browser/AlwaysIncognitoLinkInterceptor.java
  57. new file mode 100644
  58. --- /dev/null
  59. +++ b/chrome/android/java/src/org/chromium/chrome/browser/AlwaysIncognitoLinkInterceptor.java
  60. @@ -0,0 +1,80 @@
  61. +/* This Source Code Form is subject to the terms of the Mozilla Public
  62. + * License, v. 2.0. If a copy of the MPL was not distributed with this
  63. + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  64. +
  65. +package org.chromium.chrome.browser;
  66. +
  67. +import android.content.SharedPreferences;
  68. +
  69. +import org.chromium.chrome.browser.tab.EmptyTabObserver;
  70. +import org.chromium.chrome.browser.tab.Tab;
  71. +import org.chromium.chrome.browser.tab.TabImpl;
  72. +import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
  73. +import org.chromium.chrome.browser.tab.TabLaunchType;
  74. +import org.chromium.chrome.browser.tabmodel.TabModel;
  75. +import org.chromium.content_public.browser.LoadUrlParams;
  76. +import org.chromium.url.GURL;
  77. +
  78. +import java.util.HashMap;
  79. +import java.util.HashSet;
  80. +import java.util.Map;
  81. +import java.util.Set;
  82. +/**
  83. + * A {@link TabObserver} that implements the always-incognito preference behavior for links. When the preference is set
  84. + * to true, it intercepts links opened within observed {@link Tab}s and opens them in new incognito <code>Tab</code>s instead.
  85. + */
  86. +public class AlwaysIncognitoLinkInterceptor extends EmptyTabObserver {
  87. +
  88. + public static final String PREF_ALWAYS_INCOGNITO = "always_incognito";
  89. +
  90. + private final SharedPreferences alwaysIncognitoContainer;
  91. + private final Map<Tab, String> lastUrls;
  92. + private final Set<Tab> revertingTabs;
  93. +
  94. + public AlwaysIncognitoLinkInterceptor(final SharedPreferences alwaysIncognitoContainer) {
  95. +
  96. + assert alwaysIncognitoContainer != null;
  97. +
  98. + this.alwaysIncognitoContainer = alwaysIncognitoContainer;
  99. + lastUrls = new HashMap<Tab, String>();
  100. + revertingTabs = new HashSet<Tab>();
  101. + }
  102. +
  103. + @Override
  104. + public void onDestroyed(final Tab tab)
  105. + {
  106. + lastUrls.remove(tab);
  107. + revertingTabs.remove(tab);
  108. + }
  109. +
  110. + @Override
  111. + public void onUpdateUrl(Tab tab, GURL gurl) {
  112. +
  113. + if (tab == null) return;
  114. + if (gurl == null) return;
  115. + if (tab.isIncognito()) return;
  116. + if (alwaysIncognitoContainer == null) return;
  117. +
  118. + String spec = gurl.getValidSpecOrEmpty();
  119. + if (spec == null) return;
  120. +
  121. + final String lastUrl = lastUrls.put(tab, spec);
  122. +
  123. + if (!alwaysIncognitoContainer.getBoolean(PREF_ALWAYS_INCOGNITO, false)) return;
  124. + if (revertingTabs.contains(tab)) {
  125. + revertingTabs.remove(tab);
  126. + return;
  127. + }
  128. +
  129. + ((ChromeTabbedActivity)tab.getWindowAndroid().getActivity().get())
  130. + .getTabCreator(true)
  131. + .createNewTab(new LoadUrlParams(spec), TabLaunchType.FROM_LINK, tab);
  132. +
  133. + if ((spec.equals(lastUrl)) || (!tab.canGoBack())) {
  134. + // this call was triggered by a reload
  135. + } else {
  136. + revertingTabs.add(tab);
  137. + tab.goBack();
  138. + }
  139. + }
  140. +}
  141. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
  142. --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
  143. +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
  144. @@ -56,6 +56,7 @@ import org.chromium.base.supplier.UnownedUserDataSupplier;
  145. import org.chromium.base.task.PostTask;
  146. import org.chromium.cc.input.BrowserControlsState;
  147. import org.chromium.chrome.R;
  148. +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor;
  149. import org.chromium.chrome.browser.IntentHandler.IntentHandlerDelegate;
  150. import org.chromium.chrome.browser.IntentHandler.TabOpenType;
  151. import org.chromium.chrome.browser.accessibility_tab_switcher.OverviewListLayout;
  152. @@ -1766,8 +1767,9 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
  153. Bundle savedInstanceState = getSavedInstanceState();
  154. // We determine the model as soon as possible so every systems get initialized coherently.
  155. - boolean startIncognito = savedInstanceState != null
  156. - && savedInstanceState.getBoolean(IS_INCOGNITO_SELECTED, false);
  157. + boolean startIncognito = ContextUtils.getAppSharedPreferences().getBoolean(AlwaysIncognitoLinkInterceptor.PREF_ALWAYS_INCOGNITO, false)
  158. + || (savedInstanceState != null
  159. + && savedInstanceState.getBoolean(IS_INCOGNITO_SELECTED, false));
  160. mNextTabPolicySupplier = new ChromeNextTabPolicySupplier(mOverviewModeBehaviorSupplier);
  161. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
  162. --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
  163. +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
  164. @@ -101,6 +101,7 @@ import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial;
  165. import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
  166. import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager.ContextualSearchTabPromotionDelegate;
  167. import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
  168. +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor;
  169. import org.chromium.chrome.browser.dependency_injection.ChromeActivityComponent;
  170. import org.chromium.chrome.browser.dependency_injection.ModuleFactoryOverrides;
  171. import org.chromium.chrome.browser.device.DeviceClassManager;
  172. @@ -1884,6 +1885,9 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
  173. throw new IllegalStateException(
  174. "Attempting to access TabCreator before initialization");
  175. }
  176. + if (ContextUtils.getAppSharedPreferences().getBoolean(AlwaysIncognitoLinkInterceptor.PREF_ALWAYS_INCOGNITO, false)) {
  177. + incognito = true;
  178. + }
  179. return mTabCreatorManagerSupplier.get().getTabCreator(incognito);
  180. }
  181. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
  182. --- a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
  183. +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
  184. @@ -378,6 +378,12 @@ public class AppMenuPropertiesDelegateImpl implements AppMenuPropertiesDelegate
  185. }
  186. private void prepareCommonMenuItems(Menu menu, @MenuGroup int menuGroup, boolean isIncognito) {
  187. + if (ContextUtils.getAppSharedPreferences().getBoolean("always_incognito", false)) {
  188. + final MenuItem newTabOption = menu.findItem(R.id.new_tab_menu_id);
  189. + if (newTabOption != null)
  190. + newTabOption.setVisible(false);
  191. + }
  192. +
  193. // We have to iterate all menu items since same menu item ID may be associated with more
  194. // than one menu items.
  195. boolean isMenuGroupTabsVisible = TabUiFeatureUtilities.isTabGroupsAndroidEnabled(mContext)
  196. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
  197. --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
  198. +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
  199. @@ -31,6 +31,7 @@ import org.chromium.base.ContextUtils;
  200. import org.chromium.base.metrics.RecordHistogram;
  201. import org.chromium.base.supplier.Supplier;
  202. import org.chromium.chrome.R;
  203. +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor;
  204. import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCoordinator;
  205. import org.chromium.chrome.browser.contextmenu.ChromeContextMenuItem.Item;
  206. import org.chromium.chrome.browser.contextmenu.ContextMenuCoordinator.ListItemType;
  207. @@ -408,6 +409,10 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
  208. boolean hasSaveImage = false;
  209. mShowEphemeralTabNewLabel = null;
  210. + boolean always_incognito =
  211. + ContextUtils.getAppSharedPreferences().getBoolean(
  212. + AlwaysIncognitoLinkInterceptor.PREF_ALWAYS_INCOGNITO, false);
  213. +
  214. List<Pair<Integer, ModelList>> groupedItems = new ArrayList<>();
  215. if (mParams.isAnchor()) {
  216. @@ -426,6 +431,7 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
  217. linkGroup.add(createListItem(Item.OPEN_IN_NEW_TAB_IN_GROUP));
  218. }
  219. }
  220. +
  221. if (!mItemDelegate.isIncognito() && mItemDelegate.isIncognitoSupported()) {
  222. linkGroup.add(createListItem(Item.OPEN_IN_INCOGNITO_TAB));
  223. }
  224. @@ -450,7 +456,7 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
  225. }
  226. }
  227. if (FirstRunStatus.getFirstRunFlowComplete()) {
  228. - if (!mItemDelegate.isIncognito()
  229. + if ((always_incognito || !mItemDelegate.isIncognito())
  230. && UrlUtilities.isDownloadableScheme(mParams.getLinkUrl())) {
  231. linkGroup.add(createListItem(Item.SAVE_LINK_AS));
  232. }
  233. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivityLifecycleUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivityLifecycleUmaTracker.java
  234. --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivityLifecycleUmaTracker.java
  235. +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivityLifecycleUmaTracker.java
  236. @@ -39,31 +39,6 @@ public class CustomTabActivityLifecycleUmaTracker implements PauseResumeWithNati
  237. private boolean mIsInitialResume = true;
  238. private void recordIncognitoLaunchReason() {
  239. - IncognitoCustomTabIntentDataProvider incognitoProvider =
  240. - (IncognitoCustomTabIntentDataProvider) mIntentDataProvider;
  241. -
  242. - @IntentHandler.IncognitoCCTCallerId
  243. - int incognitoCCTCallerId = incognitoProvider.getFeatureIdForMetricsCollection();
  244. - RecordHistogram.recordEnumeratedHistogram("CustomTabs.IncognitoCCTCallerId",
  245. - incognitoCCTCallerId, IntentHandler.IncognitoCCTCallerId.NUM_ENTRIES);
  246. -
  247. - // Record which 1P app launched Incognito CCT.
  248. - if (incognitoCCTCallerId == IntentHandler.IncognitoCCTCallerId.GOOGLE_APPS) {
  249. - String sendersPackageName = incognitoProvider.getSendersPackageName();
  250. - @IntentHandler.ExternalAppId
  251. - int externalId = IntentHandler.mapPackageToExternalAppId(sendersPackageName);
  252. - if (externalId != IntentHandler.ExternalAppId.OTHER) {
  253. - RecordHistogram.recordEnumeratedHistogram("CustomTabs.ClientAppId.Incognito",
  254. - externalId, IntentHandler.ExternalAppId.NUM_ENTRIES);
  255. - } else {
  256. - // Using package name didn't give any meaningful insight on who launched the
  257. - // Incognito CCT, falling back to check if they provided EXTRA_APPLICATION_ID.
  258. - externalId =
  259. - IntentHandler.determineExternalIntentSource(incognitoProvider.getIntent());
  260. - RecordHistogram.recordEnumeratedHistogram("CustomTabs.ClientAppId.Incognito",
  261. - externalId, IntentHandler.ExternalAppId.NUM_ENTRIES);
  262. - }
  263. - }
  264. }
  265. private void recordUserAction() {
  266. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
  267. --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
  268. +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
  269. @@ -49,6 +49,9 @@ import org.chromium.components.browser_ui.widget.TintedDrawable;
  270. import org.chromium.components.embedder_support.util.UrlConstants;
  271. import org.chromium.device.mojom.ScreenOrientationLockType;
  272. +import org.chromium.base.ContextUtils;
  273. +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor;
  274. +
  275. import java.lang.annotation.Retention;
  276. import java.lang.annotation.RetentionPolicy;
  277. import java.util.ArrayList;
  278. @@ -726,7 +729,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
  279. @Override
  280. public boolean isIncognito() {
  281. - return false;
  282. + return ContextUtils.getAppSharedPreferences().getBoolean(AlwaysIncognitoLinkInterceptor.PREF_ALWAYS_INCOGNITO, false);
  283. }
  284. @Nullable
  285. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
  286. --- a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
  287. +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
  288. @@ -34,6 +34,9 @@ import org.chromium.content_public.browser.WebContents;
  289. import org.chromium.ui.base.WindowAndroid;
  290. import org.chromium.url.GURL;
  291. +import org.chromium.base.ContextUtils;
  292. +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor;
  293. +
  294. /**
  295. * This class attempts to preload the tab if the url is known from the intent when the profile
  296. * is created. This is done to improve startup latency.
  297. @@ -185,17 +188,22 @@ public class StartupTabPreloader implements ProfileManager.Observer, DestroyObse
  298. Intent intent = mIntentSupplier.get();
  299. GURL url = UrlFormatter.fixupUrl(getUrlFromIntent(intent));
  300. + boolean isIncognito = ContextUtils.getAppSharedPreferences().getBoolean(AlwaysIncognitoLinkInterceptor.PREF_ALWAYS_INCOGNITO, false);
  301. +
  302. + Profile profile = Profile.getLastUsedRegularProfile();
  303. ChromeTabCreator chromeTabCreator =
  304. - (ChromeTabCreator) mTabCreatorManager.getTabCreator(false);
  305. + (ChromeTabCreator) mTabCreatorManager.getTabCreator(isIncognito);
  306. WebContents webContents =
  307. - WebContentsFactory.createWebContents(Profile.getLastUsedRegularProfile(), false);
  308. + WebContentsFactory.createWebContents(
  309. + isIncognito ? profile.getPrimaryOTRProfile(true /* createIfNeeded */) : profile,
  310. + false);
  311. mLoadUrlParams = mIntentHandler.createLoadUrlParamsForIntent(url.getSpec(), intent);
  312. // Create a detached tab, but don't add it to the tab model yet. We'll do that
  313. // later if the loadUrlParams etc... match.
  314. mTab = TabBuilder.createLiveTab(false)
  315. - .setIncognito(false)
  316. + .setIncognito(isIncognito)
  317. .setLaunchType(TabLaunchType.FROM_EXTERNAL_APP)
  318. .setWindow(mWindowAndroid)
  319. .setWebContents(webContents)
  320. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
  321. --- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
  322. +++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
  323. @@ -26,6 +26,10 @@ import org.chromium.chrome.browser.profiles.Profile;
  324. import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate;
  325. import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
  326. import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
  327. +import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
  328. +import org.chromium.chrome.browser.ui.messages.snackbar.INeedSnackbarManager;
  329. +import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
  330. +import org.chromium.chrome.browser.ApplicationLifetime;
  331. import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  332. import org.chromium.components.browser_ui.settings.ManagedPreferenceDelegate;
  333. import org.chromium.components.browser_ui.settings.SettingsLauncher;
  334. @@ -40,7 +44,12 @@ import org.chromium.ui.text.SpanApplier;
  335. * Fragment to keep track of the all the privacy related preferences.
  336. */
  337. public class PrivacySettings
  338. - extends PreferenceFragmentCompat implements Preference.OnPreferenceChangeListener {
  339. + extends PreferenceFragmentCompat implements Preference.OnPreferenceChangeListener,
  340. + INeedSnackbarManager {
  341. + private SnackbarManager mSnackbarManager;
  342. + private Snackbar mSnackbar;
  343. +
  344. + private static final String PREF_ALWAYS_INCOGNITO = "always_incognito";
  345. private static final String PREF_CAN_MAKE_PAYMENT = "can_make_payment";
  346. private static final String PREF_NETWORK_PREDICTIONS = "preload_pages";
  347. private static final String PREF_HTTPS_FIRST_MODE = "https_first_mode";
  348. @@ -83,6 +92,25 @@ public class PrivacySettings
  349. (ChromeSwitchPreference) findPreference(PREF_CAN_MAKE_PAYMENT);
  350. canMakePaymentPref.setOnPreferenceChangeListener(this);
  351. + ChromeSwitchPreference alwaysIncognitoPref =
  352. + (ChromeSwitchPreference) findPreference(PREF_ALWAYS_INCOGNITO);
  353. + alwaysIncognitoPref.setOnPreferenceChangeListener(this);
  354. +
  355. + mSnackbar = Snackbar.make(getActivity().getString(R.string.ui_relaunch_notice),
  356. + new SnackbarManager.SnackbarController() {
  357. + @Override
  358. + public void onDismissNoAction(Object actionData) { }
  359. +
  360. + @Override
  361. + public void onAction(Object actionData) {
  362. + ApplicationLifetime.terminate(true);
  363. + }
  364. + }, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_UNKNOWN)
  365. + .setSingleLine(false)
  366. + .setAction(getActivity().getString(R.string.relaunch),
  367. + /*actionData*/null)
  368. + .setDuration(/*durationMs*/70000);
  369. +
  370. ChromeSwitchPreference networkPredictionPref =
  371. (ChromeSwitchPreference) findPreference(PREF_NETWORK_PREDICTIONS);
  372. networkPredictionPref.setChecked(
  373. @@ -114,6 +142,9 @@ public class PrivacySettings
  374. } else if (PREF_NETWORK_PREDICTIONS.equals(key)) {
  375. PrivacyPreferencesManagerImpl.getInstance().setNetworkPredictionEnabled(
  376. (boolean) newValue);
  377. + } else if (PREF_ALWAYS_INCOGNITO.equals(key)) {
  378. + if (!mSnackbarManager.isShowing())
  379. + mSnackbarManager.showSnackbar(mSnackbar);
  380. } else if (PREF_HTTPS_FIRST_MODE.equals(key)) {
  381. UserPrefs.get(Profile.getLastUsedRegularProfile())
  382. .setBoolean(Pref.HTTPS_ONLY_MODE_ENABLED, (boolean) newValue);
  383. @@ -191,4 +222,8 @@ public class PrivacySettings
  384. }
  385. return false;
  386. }
  387. +
  388. + public void setSnackbarManager(SnackbarManager manager) {
  389. + mSnackbarManager = manager;
  390. + }
  391. }
  392. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
  393. --- a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
  394. +++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
  395. @@ -51,6 +51,7 @@ import org.chromium.chrome.browser.safety_check.SafetyCheckSettingsFragment;
  396. import org.chromium.chrome.browser.safety_check.SafetyCheckUpdatesDelegateImpl;
  397. import org.chromium.chrome.browser.search_engines.settings.SearchEngineSettings;
  398. import org.chromium.chrome.browser.site_settings.ChromeSiteSettingsDelegate;
  399. +import org.chromium.chrome.browser.ui.messages.snackbar.INeedSnackbarManager;
  400. import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
  401. import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager.SnackbarManageable;
  402. import org.chromium.components.browser_ui.settings.FragmentSettingsLauncher;
  403. @@ -171,6 +172,9 @@ public class SettingsActivity extends ChromeBaseAppCompatActivity
  404. .getSiteSettingsDelegate());
  405. delegate.setSnackbarManager(mSnackbarManager);
  406. }
  407. + if (fragment instanceof INeedSnackbarManager) {
  408. + ((INeedSnackbarManager)fragment).setSnackbarManager(mSnackbarManager);
  409. + }
  410. }
  411. @Override
  412. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
  413. --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
  414. +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
  415. @@ -44,6 +44,10 @@ import org.chromium.url.GURL;
  416. import java.nio.ByteBuffer;
  417. +import org.chromium.base.ContextUtils;
  418. +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor;
  419. +import org.chromium.chrome.browser.tab.TabObserver;
  420. +
  421. /**
  422. * This class creates various kinds of new tabs and adds them to the right {@link TabModel}.
  423. */
  424. @@ -74,6 +78,7 @@ public class ChromeTabCreator extends TabCreator {
  425. private final Activity mActivity;
  426. private final StartupTabPreloader mStartupTabPreloader;
  427. private final boolean mIncognito;
  428. + private final TabObserver mExtraLogic;
  429. private WindowAndroid mNativeWindow;
  430. private TabModel mTabModel;
  431. @@ -96,6 +101,10 @@ public class ChromeTabCreator extends TabCreator {
  432. mNativeWindow = nativeWindow;
  433. mTabDelegateFactorySupplier = tabDelegateFactory;
  434. mIncognito = incognito;
  435. + if (!mIncognito)
  436. + mExtraLogic = new AlwaysIncognitoLinkInterceptor(ContextUtils.getAppSharedPreferences());
  437. + else
  438. + mExtraLogic = null;
  439. mOverviewNTPCreator = overviewNTPCreator;
  440. mAsyncTabParamsManager = asyncTabParamsManager;
  441. mTabModelSelectorSupplier = tabModelSelectorSupplier;
  442. @@ -259,6 +268,8 @@ public class ChromeTabCreator extends TabCreator {
  443. if (creationState == TabCreationState.LIVE_IN_FOREGROUND && !openInForeground) {
  444. creationState = TabCreationState.LIVE_IN_BACKGROUND;
  445. }
  446. + if (mExtraLogic != null)
  447. + tab.addObserver(mExtraLogic);
  448. mTabModel.addTab(tab, position, type, creationState);
  449. return tab;
  450. } finally {
  451. @@ -293,6 +304,8 @@ public class ChromeTabCreator extends TabCreator {
  452. @TabCreationState
  453. int creationState = openInForeground ? TabCreationState.LIVE_IN_FOREGROUND
  454. : TabCreationState.LIVE_IN_BACKGROUND;
  455. + if (mExtraLogic != null)
  456. + tab.addObserver(mExtraLogic);
  457. mTabModel.addTab(tab, position, type, creationState);
  458. return true;
  459. }
  460. @@ -333,7 +346,6 @@ public class ChromeTabCreator extends TabCreator {
  461. // TODO(crbug.com/1081924): Clean up the launches from SearchActivity/Chrome.
  462. public Tab launchUrlFromExternalApp(
  463. LoadUrlParams loadUrlParams, String appId, boolean forceNewTab, Intent intent) {
  464. - assert !mIncognito;
  465. // Don't re-use tabs for intents from Chrome. Note that this can be spoofed so shouldn't be
  466. // relied on for anything security sensitive.
  467. boolean isLaunchedFromChrome = TextUtils.equals(appId, mActivity.getPackageName());
  468. @@ -428,6 +440,8 @@ public class ChromeTabCreator extends TabCreator {
  469. .setSerializedCriticalPersistedTabData(serializedCriticalPersistedTabData)
  470. .build();
  471. }
  472. + if (mExtraLogic != null)
  473. + tab.addObserver(mExtraLogic);
  474. if (isIncognito != mIncognito) {
  475. throw new IllegalStateException("Incognito state mismatch. TabState: "
  476. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
  477. --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
  478. +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
  479. @@ -18,6 +18,7 @@ import androidx.core.util.AtomicFile;
  480. import org.chromium.base.Callback;
  481. import org.chromium.base.CallbackController;
  482. +import org.chromium.base.ContextUtils;
  483. import org.chromium.base.Log;
  484. import org.chromium.base.ObserverList;
  485. import org.chromium.base.StreamUtil;
  486. @@ -56,6 +57,8 @@ import org.chromium.content_public.browser.LoadUrlParams;
  487. import org.chromium.content_public.browser.UiThreadTaskTraits;
  488. import org.chromium.url.GURL;
  489. +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor;
  490. +
  491. import java.io.BufferedInputStream;
  492. import java.io.ByteArrayInputStream;
  493. import java.io.ByteArrayOutputStream;
  494. @@ -654,6 +657,13 @@ public class TabPersistentStore {
  495. }
  496. }
  497. }
  498. + if (ContextUtils.getAppSharedPreferences().getBoolean(AlwaysIncognitoLinkInterceptor.PREF_ALWAYS_INCOGNITO, false)) {
  499. + if (!isIncognito) {
  500. + Log.w(TAG, "Failed to restore tab: not in incognito mode.");
  501. + return;
  502. + }
  503. + }
  504. +
  505. TabModel model = mTabModelSelector.getModel(isIncognito);
  506. if (model.isIncognito() != isIncognito) {
  507. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappIntentDataProvider.java
  508. --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappIntentDataProvider.java
  509. +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappIntentDataProvider.java
  510. @@ -28,6 +28,9 @@ import org.chromium.chrome.browser.browserservices.intents.WebappExtras;
  511. import org.chromium.chrome.browser.flags.ActivityType;
  512. import org.chromium.components.browser_ui.widget.TintedDrawable;
  513. +import org.chromium.base.ContextUtils;
  514. +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor;
  515. +
  516. /**
  517. * Stores info about a web app.
  518. */
  519. @@ -41,6 +44,8 @@ public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider
  520. private final Intent mIntent;
  521. private final ColorProviderImpl mColorProvider;
  522. + private boolean mIsIncognito = false;
  523. +
  524. /**
  525. * Returns the toolbar color to use if a custom color is not specified by the webapp.
  526. */
  527. @@ -62,6 +67,10 @@ public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider
  528. mWebappExtras = webappExtras;
  529. mWebApkExtras = webApkExtras;
  530. mActivityType = (webApkExtras != null) ? ActivityType.WEB_APK : ActivityType.WEBAPP;
  531. +
  532. + if (ContextUtils.getAppSharedPreferences().getBoolean(AlwaysIncognitoLinkInterceptor.PREF_ALWAYS_INCOGNITO, false)) {
  533. + mIsIncognito = true;
  534. + }
  535. }
  536. @Override
  537. @@ -150,6 +159,11 @@ public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider
  538. return mWebApkExtras;
  539. }
  540. + @Override
  541. + public boolean isIncognito() {
  542. + return mIsIncognito;
  543. + }
  544. +
  545. @Override
  546. public int getDefaultOrientation() {
  547. return mWebappExtras.orientation;
  548. diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
  549. --- a/chrome/browser/flags/android/chrome_feature_list.cc
  550. +++ b/chrome/browser/flags/android/chrome_feature_list.cc
  551. @@ -445,7 +445,7 @@ const base::Feature kCCTIncognito{"CCTIncognito",
  552. base::FEATURE_ENABLED_BY_DEFAULT};
  553. const base::Feature kCCTIncognitoAvailableToThirdParty{
  554. - "CCTIncognitoAvailableToThirdParty", base::FEATURE_DISABLED_BY_DEFAULT};
  555. + "CCTIncognitoAvailableToThirdParty", base::FEATURE_ENABLED_BY_DEFAULT};
  556. const base::Feature kCCTPostMessageAPI{"CCTPostMessageAPI",
  557. base::FEATURE_ENABLED_BY_DEFAULT};
  558. diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
  559. --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
  560. +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
  561. @@ -922,6 +922,19 @@ Your Google account may have other forms of browsing history like searches and a
  562. <message name="IDS_CLEAR_BROWSING_HISTORY_SUMMARY_SYNCED_NO_LINK" desc="A text for the basic tab explaining browsing history for users with history sync. This version is shown when the link to MyActivity is displayed separately.">
  563. Clears history from all synced devices.
  564. </message>
  565. + <!-- always incognito -->
  566. + <message name="IDS_ALWAYS_INCOGNITO_TITLE" desc="Title for always incognito mode">
  567. + Open links in incognito tabs always
  568. + </message>
  569. + <message name="IDS_ALWAYS_INCOGNITO_SUMMARY" desc="Summary for always incognito mode">
  570. + Opens links in incognito tabs when you click on new tab or on a link
  571. + </message>
  572. + <message name="IDS_RELAUNCH" desc="Summary for always incognito mode">
  573. + Relaunch
  574. + </message>
  575. + <message name="IDS_UI_RELAUNCH_NOTICE" desc="Summary for always incognito mode">
  576. + Your changes will take effect the next time you relaunch Bromite.
  577. + </message>
  578. <message name="IDS_CLEAR_BROWSING_HISTORY_SUMMARY_SIGNED_IN" desc="A text explaining other forms of activity for signed in users.">
  579. Clears history and autocompletions in the address bar. Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;link&gt;</ph>myactivity.google.com<ph name="END_LINK">&lt;/link&gt;</ph>.
  580. </message>
  581. diff --git a/chrome/browser/ui/messages/android/BUILD.gn b/chrome/browser/ui/messages/android/BUILD.gn
  582. --- a/chrome/browser/ui/messages/android/BUILD.gn
  583. +++ b/chrome/browser/ui/messages/android/BUILD.gn
  584. @@ -22,6 +22,7 @@ android_resources("java_resources") {
  585. android_library("java") {
  586. sources = [
  587. "java/src/org/chromium/chrome/browser/ui/messages/infobar/SimpleConfirmInfoBarBuilder.java",
  588. + "java/src/org/chromium/chrome/browser/ui/messages/snackbar/INeedSnackbarManager.java",
  589. "java/src/org/chromium/chrome/browser/ui/messages/snackbar/Snackbar.java",
  590. "java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarCollection.java",
  591. "java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java",
  592. diff --git a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/INeedSnackbarManager.java b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/INeedSnackbarManager.java
  593. new file mode 100644
  594. --- /dev/null
  595. +++ b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/INeedSnackbarManager.java
  596. @@ -0,0 +1,27 @@
  597. +/*
  598. + This file is part of Bromite.
  599. +
  600. + Bromite is free software: you can redistribute it and/or modify
  601. + it under the terms of the GNU General Public License as published by
  602. + the Free Software Foundation, either version 3 of the License, or
  603. + (at your option) any later version.
  604. +
  605. + Bromite is distributed in the hope that it will be useful,
  606. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  607. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  608. + GNU General Public License for more details.
  609. +
  610. + You should have received a copy of the GNU General Public License
  611. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  612. +*/
  613. +
  614. +package org.chromium.chrome.browser.ui.messages.snackbar;
  615. +
  616. +import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
  617. +
  618. +/**
  619. + * An interface that allows using snackbars in the settings
  620. + */
  621. +public interface INeedSnackbarManager {
  622. + void setSnackbarManager(SnackbarManager manager);
  623. +}
  624. --
  625. 2.20.1