diff --git a/CHANGELOG.md b/CHANGELOG.md index ba878eec..e6f70f0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 89.0.4389.100 +* enable AImageReader by default (fixes https://github.com/bromite/bromite/issues/1005) +* fix missing flag for AImageReader +* move incognito snapshots flag to proper section (fixes https://github.com/bromite/bromite/issues/1006) +* add missing icon for exit menu +* implement SAF for bookmarks export functionality (thanks to @uazo, fixes https://github.com/bromite/bromite/issues/831) + # 89.0.4389.92 * updated zh_CN translations (thanks to @zhmars, https://github.com/bromite/bromite/pull/1000) * introduce Alt+D hotkey to focus address bar (fixes https://github.com/bromite/bromite/issues/979) diff --git a/build/RELEASE b/build/RELEASE index 638727b1..614a4eff 100644 --- a/build/RELEASE +++ b/build/RELEASE @@ -1 +1 @@ -89.0.4389.92 +89.0.4389.100 diff --git a/build/bromite_patches_list.txt b/build/bromite_patches_list.txt index 0a36dfbf..038f9c6b 100644 --- a/build/bromite_patches_list.txt +++ b/build/bromite_patches_list.txt @@ -54,6 +54,7 @@ Add-flags-to-disable-device-motion-orientation-APIs.patch Disable-metrics-on-all-I-O-threads.patch Always-respect-async-dns-flag-regardless-of-SDK-version.patch Add-flag-to-configure-maximum-connections-per-host.patch +Do-not-ignore-download-location-prompt-setting.patch Add-bookmark-import-export-actions.patch Add-an-always-incognito-mode.patch Add-custom-tab-intents-privacy-option.patch @@ -80,7 +81,6 @@ Offer-builtin-autocomplete-for-chrome-flags.patch Do-not-grant-notifications-to-default-search-engine.patch Add-flag-to-disable-IPv6-probes.patch Add-a-proxy-configuration-page.patch -Do-not-ignore-download-location-prompt-setting.patch Disable-previews-by-default.patch Use-4-tile-rows-never-show-logo.patch Disable-metrics-collection-for-NTP-tiles.patch diff --git a/build/patches/AImageReader-CFI-crash-mitigations.patch b/build/patches/AImageReader-CFI-crash-mitigations.patch index a94a5767..a290a25c 100644 --- a/build/patches/AImageReader-CFI-crash-mitigations.patch +++ b/build/patches/AImageReader-CFI-crash-mitigations.patch @@ -22,8 +22,7 @@ See discussions at: base/android/android_image_reader_compat.cc | 8 +++++++- base/android/android_image_reader_compat.h | 4 ++++ chrome/browser/flag-metadata.json | 2 +- - gpu/config/gpu_driver_bug_list.json | 16 ++++++++++++++++ - gpu/config/gpu_finch_features.cc | 11 ++++++++++- + gpu/config/gpu_finch_features.cc | 5 +++++ gpu/config/gpu_finch_features.h | 1 + gpu/config/gpu_util.cc | 8 ++++++++ gpu/config/gpu_workaround_list.txt | 1 + @@ -31,7 +30,7 @@ See discussions at: gpu/ipc/service/stream_texture_android.cc | 11 ++++++++++- media/base/media_switches.cc | 4 ++++ media/base/media_switches.h | 1 + - 12 files changed, 68 insertions(+), 4 deletions(-) + 11 files changed, 47 insertions(+), 3 deletions(-) diff --git a/base/android/android_image_reader_compat.cc b/base/android/android_image_reader_compat.cc --- a/base/android/android_image_reader_compat.cc @@ -83,41 +82,15 @@ diff --git a/base/android/android_image_reader_compat.h b/base/android/android_i diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json -@@ -1724,7 +1724,7 @@ +@@ -1772,7 +1772,7 @@ { - "name": "enable-heavy-ad-intervention", - "owners": [ "johnidel", "jkarlin" ], + "name": "enable-image-reader", + "owners": [ "vikassoni", "liberato" ], - "expiry_milestone": 90 + "expiry_milestone": -1 }, { - "name": "enable-heuristic-stylus-palm-rejection", -diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json ---- a/gpu/config/gpu_driver_bug_list.json -+++ b/gpu/config/gpu_driver_bug_list.json -@@ -3254,6 +3254,22 @@ - "dont_delete_source_texture_for_egl_image" - ] - }, -+ { -+ "id":335, -+ "cr_bugs": [1051705], -+ "description": "Disable AImageReader on ARM GPUs", -+ "os": { -+ "type": "android", -+ "version": { -+ "op": "<", -+ "value": "10" -+ } -+ }, -+ "gl_vendor": "ARM.*", -+ "features": [ -+ "disable_aimagereader" -+ ] -+ }, - { - "id": 336, - "cr_bugs": [625785], + "name": "enable-immersive-fullscreen-toolbar", diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc --- a/gpu/config/gpu_finch_features.cc +++ b/gpu/config/gpu_finch_features.cc @@ -133,19 +106,6 @@ diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc // Used to limit GL version to 2.0 for skia raster on Android. const base::Feature kUseGles2ForOopR{"UseGles2ForOopR", base::FEATURE_DISABLED_BY_DEFAULT}; -@@ -55,7 +60,11 @@ const base::FeatureParam kAndroidSurfaceControlBlocklist{ - - // Use AImageReader for MediaCodec and MediaPlyer on android. - const base::Feature kAImageReader{"AImageReader", -- base::FEATURE_ENABLED_BY_DEFAULT}; -+#ifdef ARCH_CPU_ARM64 -+ base::FEATURE_DISABLED_BY_DEFAULT}; -+#else -+ base::FEATURE_ENABLED_BY_DEFAULT}; -+#endif - - // If webview-draw-functor-uses-vulkan is set, use vulkan for composite and - // raster. diff --git a/gpu/config/gpu_finch_features.h b/gpu/config/gpu_finch_features.h --- a/gpu/config/gpu_finch_features.h +++ b/gpu/config/gpu_finch_features.h diff --git a/build/patches/Add-a-flag-to-allow-screenshots-in-Incognito-mode.patch b/build/patches/Add-a-flag-to-allow-screenshots-in-Incognito-mode.patch index f6c54c50..7c8426bc 100644 --- a/build/patches/Add-a-flag-to-allow-screenshots-in-Incognito-mode.patch +++ b/build/patches/Add-a-flag-to-allow-screenshots-in-Incognito-mode.patch @@ -17,19 +17,19 @@ See also: diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc -@@ -5387,6 +5387,12 @@ const FeatureEntry kFeatureEntries[] = { - SINGLE_VALUE_TYPE(switches::kEnableGPUServiceLogging)}, +@@ -3040,6 +3040,12 @@ const FeatureEntry kFeatureEntries[] = { + FEATURE_VALUE_TYPE(ash::features::kSystemTrayMicGainSetting)}, + #endif // BUILDFLAG(IS_CHROMEOS_ASH) - #if !defined(OS_ANDROID) +#if defined(OS_ANDROID) + {switches::kEnableIncognitoSnapshotsInAndroidRecents, flag_descriptions::kEnableIncognitoSnapshotsInAndroidRecentsName, + flag_descriptions::kEnableIncognitoSnapshotsInAndroidRecentsDescription, kOsAndroid, + SINGLE_VALUE_TYPE(switches::kEnableIncognitoSnapshotsInAndroidRecents)}, +#endif + - {"hardware-media-key-handling", - flag_descriptions::kHardwareMediaKeyHandling, - flag_descriptions::kHardwareMediaKeyHandlingDescription, kOsDesktop, + #if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && !defined(OS_ANDROID) + { + "enable-accelerated-video-decode", diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc diff --git a/build/patches/Add-an-always-incognito-mode.patch b/build/patches/Add-an-always-incognito-mode.patch index 3588db30..93a29e04 100644 --- a/build/patches/Add-an-always-incognito-mode.patch +++ b/build/patches/Add-an-always-incognito-mode.patch @@ -454,7 +454,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappI diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc -@@ -394,7 +394,7 @@ const base::Feature kCCTIncognito{"CCTIncognito", +@@ -395,7 +395,7 @@ const base::Feature kCCTIncognito{"CCTIncognito", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kCCTIncognitoAvailableToThirdParty{ @@ -466,7 +466,7 @@ diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browse diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd -@@ -844,6 +844,13 @@ Your Google account may have other forms of browsing history like searches and a +@@ -856,6 +856,13 @@ Your Google account may have other forms of browsing history like searches and a Clears history and autocompletions in the address bar. diff --git a/build/patches/Add-bookmark-import-export-actions.patch b/build/patches/Add-bookmark-import-export-actions.patch index b3f033ca..4bf85dcd 100644 --- a/build/patches/Add-bookmark-import-export-actions.patch +++ b/build/patches/Add-bookmark-import-export-actions.patch @@ -6,31 +6,128 @@ Add bookmark import/export actions in bookmarks activity and page Reduce permissions needed for bookmarks import/export Completely remove contacts picker permission from the file dialog --- + base/android/content_uri_utils.cc | 10 + + base/android/content_uri_utils.h | 4 + + .../org/chromium/base/ContentUriUtils.java | 32 ++ chrome/android/java/AndroidManifest.xml | 1 - .../res/menu/bookmark_action_bar_menu.xml | 14 + .../browser/bookmarks/BookmarkActionBar.java | 12 + - .../browser/bookmarks/BookmarkActivity.java | 23 ++ - .../browser/bookmarks/BookmarkBridge.java | 63 +++++ + .../browser/bookmarks/BookmarkActivity.java | 28 ++ + .../browser/bookmarks/BookmarkBridge.java | 277 +++++++++++++++++ .../browser/bookmarks/BookmarkDelegate.java | 10 + - .../browser/bookmarks/BookmarkManager.java | 19 ++ - .../browser/bookmarks/BookmarkPage.java | 5 +- + .../browser/bookmarks/BookmarkManager.java | 22 ++ + .../browser/bookmarks/BookmarkPage.java | 9 +- .../native_page/NativePageFactory.java | 3 +- chrome/browser/BUILD.gn | 6 +- - .../android/bookmarks/bookmark_bridge.cc | 242 ++++++++++++++++++ - .../android/bookmarks/bookmark_bridge.h | 24 +- + chrome/browser/about_flags.cc | 6 + + .../android/bookmarks/bookmark_bridge.cc | 284 ++++++++++++++++++ + .../android/bookmarks/bookmark_bridge.h | 28 +- + .../browser/bookmarks/bookmark_html_writer.cc | 7 +- + .../dialogs/DownloadLocationCustomView.java | 7 +- + .../DownloadLocationDialogCoordinator.java | 10 +- + chrome/browser/flag_descriptions.cc | 5 + + chrome/browser/flag_descriptions.h | 3 + + .../flags/android/chrome_feature_list.cc | 4 + + .../flags/android/chrome_feature_list.h | 1 + + .../browser/flags/ChromeFeatureList.java | 1 + chrome/browser/importer/profile_writer.cc | 12 + chrome/browser/importer/profile_writer.h | 6 + - .../strings/android_chrome_strings.grd | 6 + + .../preferences/ChromePreferenceKeys.java | 3 + + .../strings/android_chrome_strings.grd | 18 ++ chrome/common/BUILD.gn | 3 + chrome/utility/BUILD.gn | 7 +- .../utility/importer/bookmark_html_reader.cc | 27 +- .../utility/importer/bookmark_html_reader.h | 8 + .../chromium/ui/base/SelectFileDialog.java | 18 +- + .../java/strings/android_ui_strings.grd | 3 + ui/shell_dialogs/select_file_dialog.h | 2 + .../select_file_dialog_android.cc | 6 + ui/shell_dialogs/select_file_dialog_android.h | 2 + - 23 files changed, 505 insertions(+), 14 deletions(-) + 37 files changed, 876 insertions(+), 23 deletions(-) +diff --git a/base/android/content_uri_utils.cc b/base/android/content_uri_utils.cc +--- a/base/android/content_uri_utils.cc ++++ b/base/android/content_uri_utils.cc +@@ -30,6 +30,16 @@ File OpenContentUriForRead(const FilePath& content_uri) { + return File(fd); + } + ++File OpenContentUriForWrite(const FilePath& content_uri) { ++ JNIEnv* env = base::android::AttachCurrentThread(); ++ ScopedJavaLocalRef j_uri = ++ ConvertUTF8ToJavaString(env, content_uri.value()); ++ jint fd = Java_ContentUriUtils_openContentUriForWrite(env, j_uri); ++ if (fd < 0) ++ return File(); ++ return File(fd); ++} ++ + std::string GetContentUriMimeType(const FilePath& content_uri) { + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaLocalRef j_uri = +diff --git a/base/android/content_uri_utils.h b/base/android/content_uri_utils.h +--- a/base/android/content_uri_utils.h ++++ b/base/android/content_uri_utils.h +@@ -17,6 +17,10 @@ namespace base { + // Returns -1 if the URI is invalid. + BASE_EXPORT File OpenContentUriForRead(const FilePath& content_uri); + ++// Opens a content URI for write and returns the file descriptor to the caller. ++// Returns -1 if the URI is invalid. ++BASE_EXPORT File OpenContentUriForWrite(const FilePath& content_uri); ++ + // Check whether a content URI exists. + BASE_EXPORT bool ContentUriExists(const FilePath& content_uri); + +diff --git a/base/android/java/src/org/chromium/base/ContentUriUtils.java b/base/android/java/src/org/chromium/base/ContentUriUtils.java +--- a/base/android/java/src/org/chromium/base/ContentUriUtils.java ++++ b/base/android/java/src/org/chromium/base/ContentUriUtils.java +@@ -23,6 +23,9 @@ import org.chromium.base.annotations.CalledByNative; + import java.io.File; + import java.io.IOException; + ++import android.system.Os; ++import android.content.ContentProviderClient; ++ + /** + * This class provides methods to access content URI schemes. + */ +@@ -89,6 +92,35 @@ public abstract class ContentUriUtils { + return -1; + } + ++ @CalledByNative ++ public static int openContentUriForWrite(String uriString) { ++ try { ++ Uri uri = Uri.parse(uriString); ++ ContentResolver resolver = ContextUtils.getApplicationContext().getContentResolver(); ++ ContentProviderClient client = resolver.acquireContentProviderClient( ++ uri.getAuthority()); ++ ParcelFileDescriptor pfd = client.openFile(uri, "rw"); ++ int fd = pfd.detachFd(); ++ client.close(); ++ return fd; ++ } catch (Exception e) { ++ Log.e(TAG, "Cannot open intermediate Uri.", e); ++ } ++ return -1; ++ } ++ ++ public static String getFilePathFromContentUri(Uri uri) { ++ String path = null; ++ try { ++ ContentResolver resolver = ContextUtils.getApplicationContext().getContentResolver(); ++ ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r"); ++ path = Os.readlink("/proc/self/fd/" + pfd.getFd()); ++ pfd.close(); ++ } catch (Throwable t) { ++ } ++ return path; ++ } ++ + /** + * Check whether a content URI exists. + * diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml @@ -112,15 +209,18 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActivity.java --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActivity.java -@@ -15,6 +15,7 @@ import org.chromium.chrome.browser.IntentHandler; +@@ -15,6 +15,10 @@ import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.SnackbarActivity; import org.chromium.components.bookmarks.BookmarkId; import org.chromium.components.embedder_support.util.UrlConstants; +import org.chromium.ui.base.ActivityWindowAndroid; ++ ++import org.chromium.ui.modaldialog.ModalDialogManager; ++import org.chromium.components.browser_ui.modaldialog.AppModalPresenter; /** * The activity that displays the bookmark UI on the phone. It keeps a {@link BookmarkManager} -@@ -24,6 +25,7 @@ import org.chromium.components.embedder_support.util.UrlConstants; +@@ -24,6 +28,7 @@ import org.chromium.components.embedder_support.util.UrlConstants; public class BookmarkActivity extends SnackbarActivity { private BookmarkManager mBookmarkManager; @@ -128,7 +228,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm static final int EDIT_BOOKMARK_REQUEST_CODE = 14; public static final String INTENT_VISIT_BOOKMARK_ID = "BookmarkEditActivity.VisitBookmarkId"; -@@ -38,6 +40,18 @@ public class BookmarkActivity extends SnackbarActivity { +@@ -38,6 +43,20 @@ public class BookmarkActivity extends SnackbarActivity { if (TextUtils.isEmpty(url)) url = UrlConstants.BOOKMARKS_URL; mBookmarkManager.updateForUrl(url); setContentView(mBookmarkManager.getView()); @@ -136,7 +236,9 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm + final boolean listenToActivityState = true; + mWindowAndroid = new ActivityWindowAndroid(this, listenToActivityState); + mWindowAndroid.restoreInstanceState(savedInstanceState); -+ mBookmarkManager.setWindow(mWindowAndroid); ++ mBookmarkManager.setWindow(mWindowAndroid, ++ new ModalDialogManager( ++ new AppModalPresenter(this), ModalDialogManager.ModalDialogType.APP)); + } + + @Override @@ -147,7 +249,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm } @Override -@@ -54,6 +68,7 @@ public class BookmarkActivity extends SnackbarActivity { +@@ -54,6 +73,7 @@ public class BookmarkActivity extends SnackbarActivity { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -155,7 +257,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm if (requestCode == EDIT_BOOKMARK_REQUEST_CODE && resultCode == RESULT_OK) { BookmarkId bookmarkId = BookmarkId.getBookmarkIdFromString(data.getStringExtra( INTENT_VISIT_BOOKMARK_ID)); -@@ -61,6 +76,14 @@ public class BookmarkActivity extends SnackbarActivity { +@@ -61,6 +81,14 @@ public class BookmarkActivity extends SnackbarActivity { } } @@ -163,7 +265,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm + public void onRequestPermissionsResult( + int requestCode, String[] permissions, int[] grantResults) { + if (mWindowAndroid.handlePermissionResult(requestCode, permissions, grantResults)) -+ return; ++ return; + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + @@ -173,33 +275,61 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java -@@ -4,7 +4,13 @@ +@@ -4,7 +4,19 @@ package org.chromium.chrome.browser.bookmarks; +import android.content.Intent; +import android.content.Context; +import android.content.pm.PackageManager; ++import android.content.DialogInterface; ++import android.content.Intent; +import android.net.Uri; - import android.os.SystemClock; ++import android.content.ContentResolver; +import android.provider.Browser; ++import android.provider.DocumentsContract; +import android.Manifest.permission; ++import androidx.appcompat.app.AlertDialog; + import android.os.SystemClock; ++import android.os.Build; import android.text.TextUtils; import android.util.Pair; -@@ -27,6 +33,11 @@ import org.chromium.components.url_formatter.UrlFormatter; +@@ -27,8 +39,33 @@ import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.content_public.browser.WebContents; import org.chromium.url.GURL; ++import org.chromium.base.ContentUriUtils; ++import org.chromium.chrome.R; +import org.chromium.chrome.browser.document.ChromeLauncherActivity; +import org.chromium.chrome.browser.IntentHandler; ++import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; ++import org.chromium.chrome.browser.preferences.SharedPreferencesManager; ++import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.ui.base.PageTransition; +import org.chromium.ui.base.WindowAndroid; ++import org.chromium.ui.modaldialog.ModalDialogManager; ++ ++import android.view.View; ++import android.view.LayoutInflater; ++import org.chromium.ui.modelutil.PropertyModel; ++import org.chromium.ui.modaldialog.ModalDialogProperties; ++import org.chromium.ui.modaldialog.DialogDismissalCause; ++import org.chromium.chrome.browser.download.DownloadLocationDialogType; ++import org.chromium.chrome.browser.download.dialogs.DownloadLocationDialogController; ++import org.chromium.chrome.browser.download.dialogs.DownloadLocationDialogCoordinator; ++import org.chromium.chrome.browser.download.dialogs.DownloadLocationCustomView; ++import org.chromium.chrome.browser.download.DirectoryOption; ++import android.content.res.Resources; ++import org.chromium.base.task.AsyncTask; + import java.util.ArrayList; import java.util.List; ++import java.io.File; -@@ -585,6 +596,38 @@ public class BookmarkBridge { + /** + * Provides the communication channel for Android to fetch and manipulate the +@@ -585,6 +622,210 @@ public class BookmarkBridge { mNativeBookmarkBridge, BookmarkBridge.this, id.getId(), id.getType()); } @@ -216,59 +346,247 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm + * Export bookmarks to a path selected by the user. + * @param window The current window of the bookmarks activity or page. + */ -+ public void exportBookmarks(WindowAndroid window) { ++ public void exportBookmarks(WindowAndroid window, ModalDialogManager modalDialogManager) { + assert mIsNativeBookmarkModelLoaded; -+ // check if we have the correct write permission -+ if (window.hasPermission(permission.WRITE_EXTERNAL_STORAGE)) { -+ exportBookmarksImpl(); -+ } else { -+ String[] requestPermissions = new String[] {permission.WRITE_EXTERNAL_STORAGE}; -+ window.requestPermissions(requestPermissions, (permissions, grantResults) -> { -+ if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { -+ exportBookmarksImpl(); -+ } -+ }); -+ }; ++ if (ChromeFeatureList.isEnabled(ChromeFeatureList.BOOKMARKS_EXPORT_USESAF) || ++ Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) ++ exportBookmarksImplUseSaf(window); ++ else ++ exportBookmarksImplUseFile(window, modalDialogManager); + } + -+ private void exportBookmarksImpl() { -+ BookmarkBridgeJni.get().exportBookmarks(mNativeBookmarkBridge, BookmarkBridge.this); ++ private void exportBookmarksImplUseSaf(WindowAndroid window) { ++ Context context = window.getContext().get(); ++ ++ // standard name for boorkmark file ++ final String standardBoorkmarkName = "bookmarks.html"; ++ ++ // use the fileSelector and saf asking user for the file ++ Intent fileSelector = new Intent(Intent.ACTION_CREATE_DOCUMENT); ++ fileSelector.addCategory(Intent.CATEGORY_OPENABLE); ++ fileSelector.setType("text/html"); ++ fileSelector.putExtra(Intent.EXTRA_TITLE, standardBoorkmarkName); ++ fileSelector.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | ++ Intent.FLAG_GRANT_READ_URI_PERMISSION | ++ Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); ++ ++ // get last exported uri path, if any ++ SharedPreferencesManager sharedPrefs = SharedPreferencesManager.getInstance(); ++ String bookmarksPath = sharedPrefs.readString(ChromePreferenceKeys.BOOKMARKS_LAST_EXPORT_URI, standardBoorkmarkName); ++ Uri lastSelectedUri = Uri.parse(bookmarksPath); ++ ++ // prepare delegate for file selector ++ DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { ++ @Override ++ public void onClick(DialogInterface dialog, int button) { ++ if (button == AlertDialog.BUTTON_NEGATIVE) { ++ window.showIntent(fileSelector, ++ new WindowAndroid.IntentCallback() { ++ @Override ++ public void onIntentCompleted(WindowAndroid window, int resultCode, Intent data) { ++ if (data == null) return; ++ Uri filePath = data.getData(); ++ doExportBookmarksImpl(window, filePath); ++ } ++ }, ++ null); ++ } else { ++ if (dialog!=null) dialog.dismiss(); ++ doExportBookmarksImpl(window, lastSelectedUri); ++ } ++ } ++ }; ++ ++ // as a workaround for https://issuetracker.google.com/issues/37136466 ++ // ask to overwrite if is a valid uri and the file is present ++ if (DocumentsContract.isDocumentUri(context, lastSelectedUri)) { ++ AsyncTask checkUriTask = new AsyncTask() { ++ boolean uriExists = false; ++ String actualFilePath = null; ++ ++ @Override ++ protected Void doInBackground() { ++ uriExists = ContentUriUtils.contentUriExists(lastSelectedUri.toString()); ++ if (uriExists) { ++ actualFilePath = ContentUriUtils.getFilePathFromContentUri(lastSelectedUri); ++ // get real actual file name on disk ++ if (actualFilePath==null) actualFilePath = lastSelectedUri.toString(); ++ // set file name to last exported file name ++ fileSelector.putExtra(Intent.EXTRA_TITLE, ++ ContentUriUtils.getDisplayName(lastSelectedUri, context, ++ DocumentsContract.Document.COLUMN_DISPLAY_NAME)); ++ } ++ return null; ++ } ++ ++ @Override ++ protected void onPostExecute(Void result) { ++ // check for permissions ++ if (uriExists) { ++ AlertDialog.Builder alert = ++ new AlertDialog.Builder(context, R.style.Theme_Chromium_AlertDialog); ++ AlertDialog alertDialog = ++ alert.setTitle(R.string.export_bookmarks_alert_title) ++ .setMessage(context.getString(R.string.export_bookmarks_alert_message, actualFilePath)) ++ .setPositiveButton( ++ R.string.export_bookmarks_alert_message_yes, onClickListener) ++ .setNegativeButton(R.string.export_bookmarks_alert_message_no, onClickListener) ++ .create(); ++ alertDialog.getDelegate().setHandleNativeActionModesEnabled(false); ++ ++ // show dialog asking for overwrite ++ alertDialog.show(); ++ return; ++ } else { ++ onClickListener.onClick(null, AlertDialog.BUTTON_NEGATIVE); ++ } ++ } ++ }; ++ checkUriTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); ++ return; ++ } ++ ++ // actually open the file selector ++ onClickListener.onClick(null, AlertDialog.BUTTON_NEGATIVE); ++ } ++ ++ private void doExportBookmarksImpl(WindowAndroid window, Uri filePath) { ++ ContentResolver resolver = ContextUtils.getApplicationContext().getContentResolver(); ++ // since we want to persist the uri in settings, ask for persistable permissions ++ resolver.takePersistableUriPermission(filePath, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | ++ Intent.FLAG_GRANT_READ_URI_PERMISSION); ++ ++ BookmarkBridgeJni.get().exportBookmarks(mNativeBookmarkBridge, BookmarkBridge.this, ++ window, filePath.toString()); ++ } ++ ++ private void exportBookmarksImplUseFile(WindowAndroid window, ModalDialogManager modalDialogManager) { ++ Context context = window.getContext().get(); ++ ++ // standard name for boorkmark file ++ final String standardBoorkmarkName = "bookmarks.html"; ++ ++ // use the download ui and standard file saving ++ DownloadLocationDialogController controller = new DownloadLocationDialogController() { ++ @Override ++ public void onDownloadLocationDialogComplete(String returnedPath) {} ++ ++ @Override ++ public void onDownloadLocationDialogCanceled() {} ++ }; ++ ++ DownloadLocationDialogCoordinator dialog = new DownloadLocationDialogCoordinator() { ++ @Override ++ protected void onDirectoryOptionsRetrieved(ArrayList dirs) { ++ if (mDialogModel != null) return; ++ ++ // Actually show the dialog. ++ mCustomView = (DownloadLocationCustomView) LayoutInflater.from(mContext).inflate( ++ R.layout.download_location_dialog, null); ++ mCustomView.initialize( ++ DownloadLocationDialogType.DEFAULT, new File(standardBoorkmarkName), ++ /*totalBytes*/ 0, context.getString(R.string.export_bookmarks_alert_title)); ++ mCustomView.mDontShowAgain.setVisibility(View.GONE); ++ ++ Resources resources = mContext.getResources(); ++ mDialogModel = new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS) ++ .with(ModalDialogProperties.CONTROLLER, this) ++ .with(ModalDialogProperties.CUSTOM_VIEW, mCustomView) ++ .with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, resources, ++ R.string.export_bookmarks) ++ .with(ModalDialogProperties.PRIMARY_BUTTON_FILLED, true) ++ .with(ModalDialogProperties.NEGATIVE_BUTTON_TEXT, resources, ++ R.string.cancel) ++ .build(); ++ ++ mModalDialogManager.showDialog(mDialogModel, ModalDialogManager.ModalDialogType.APP); ++ } ++ ++ @Override ++ public void onDismiss(PropertyModel model, int dismissalCause) { ++ switch (dismissalCause) { ++ case DialogDismissalCause.POSITIVE_BUTTON_CLICKED: ++ { ++ String fileName = mCustomView.getFileName(); ++ String directory = mCustomView.getDirectoryOption().location; ++ if (fileName != null && directory != null) { ++ File file = new File(directory, fileName); ++ ++ if (window.hasPermission(permission.WRITE_EXTERNAL_STORAGE)) { ++ BookmarkBridgeJni.get().exportBookmarks(mNativeBookmarkBridge, ++ BookmarkBridge.this, window, file.getPath()); ++ } else { ++ String[] requestPermissions = new String[] {permission.WRITE_EXTERNAL_STORAGE}; ++ window.requestPermissions(requestPermissions, (permissions, grantResults) -> { ++ if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { ++ BookmarkBridgeJni.get().exportBookmarks(mNativeBookmarkBridge, ++ BookmarkBridge.this, window, file.getPath()); ++ } ++ }); ++ }; ++ } ++ } ++ break; ++ } ++ mDialogModel = null; ++ mCustomView = null; ++ } ++ }; ++ dialog.initialize(controller); ++ dialog.showDialog(context, modalDialogManager, /*totalBytes*/ 0, ++ DownloadLocationDialogType.DEFAULT, /*suggestedPath*/ ""); + } + /** * Synchronously gets a list of bookmarks that match the specified search query. * @param query Keyword used for searching bookmarks. -@@ -1016,6 +1059,24 @@ public class BookmarkBridge { +@@ -1016,6 +1257,39 @@ public class BookmarkBridge { depthList.add(depth); } + @CalledByNative -+ public void bookmarksExported(String bookmarksPath) { -+ Context context = ContextUtils.getApplicationContext(); ++ public void bookmarksExported(WindowAndroid window, String bookmarksPath, boolean success) { ++ Uri uri = Uri.parse(bookmarksPath); + -+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("file://" + bookmarksPath)); -+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, -+ context.getPackageName()); -+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); -+ intent.putExtra(IntentHandler.EXTRA_PAGE_TRANSITION_TYPE, PageTransition.AUTO_BOOKMARK); ++ if (success == false) { ++ ((Activity)window.getContext().get()).runOnUiThread(new Runnable() { ++ public void run() { ++ window.showError(R.string.saving_file_error); ++ } ++ }); ++ } else { ++ SharedPreferencesManager sharedPrefs = SharedPreferencesManager.getInstance(); ++ sharedPrefs.writeString(ChromePreferenceKeys.BOOKMARKS_LAST_EXPORT_URI, bookmarksPath); + -+ // If the bookmark manager is shown in a tab on a phone (rather than in a separate -+ // activity) the component name may be null. Send the intent through -+ // ChromeLauncherActivity instead to avoid crashing. See crbug.com/615012. -+ intent.setClass(context, ChromeLauncherActivity.class); ++ Context context = ContextUtils.getApplicationContext(); + -+ IntentHandler.startActivityForTrustedIntent(intent); ++ Intent intent = new Intent(Intent.ACTION_VIEW, ++ ContentUriUtils.isContentUri(bookmarksPath) ? ++ Uri.parse(bookmarksPath) : Uri.parse("file://" + bookmarksPath)); ++ intent.putExtra(Browser.EXTRA_APPLICATION_ID, ++ context.getPackageName()); ++ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ++ intent.putExtra(IntentHandler.EXTRA_PAGE_TRANSITION_TYPE, PageTransition.AUTO_BOOKMARK); ++ ++ // If the bookmark manager is shown in a tab on a phone (rather than in a separate ++ // activity) the component name may be null. Send the intent through ++ // ChromeLauncherActivity instead to avoid crashing. See crbug.com/615012. ++ intent.setClass(context, ChromeLauncherActivity.class); ++ ++ IntentHandler.startActivityForTrustedIntent(intent); ++ } + } + private static List> createPairsList(int[] left, int[] right) { List> pairList = new ArrayList>(); for (int i = 0; i < left.length; i++) { -@@ -1083,6 +1144,8 @@ public class BookmarkBridge { +@@ -1083,6 +1357,9 @@ public class BookmarkBridge { int getChildCount(long nativeBookmarkBridge, BookmarkBridge caller, long id, int type); void getChildIDs(long nativeBookmarkBridge, BookmarkBridge caller, long id, int type, List bookmarksList); + void importBookmarks(long nativeBookmarkBridge, BookmarkBridge caller, WindowAndroid window); -+ void exportBookmarks(long nativeBookmarkBridge, BookmarkBridge caller); ++ void exportBookmarks(long nativeBookmarkBridge, BookmarkBridge caller, WindowAndroid window, ++ String export_path); BookmarkId getChildAt( long nativeBookmarkBridge, BookmarkBridge caller, long id, int type, int index); int getTotalBookmarkCount( @@ -295,37 +613,40 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java -@@ -33,6 +33,7 @@ import org.chromium.components.browser_ui.util.ConversionUtils; +@@ -33,6 +33,8 @@ import org.chromium.components.browser_ui.util.ConversionUtils; import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate; import org.chromium.components.browser_ui.widget.selectable_list.SelectableListLayout; import org.chromium.components.browser_ui.widget.selectable_list.SelectableListToolbar.SearchDelegate; +import org.chromium.ui.base.ActivityWindowAndroid; ++import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate; import org.chromium.components.favicon.LargeIconBridge; import org.chromium.url.GURL; -@@ -55,6 +56,7 @@ public class BookmarkManager +@@ -55,6 +57,8 @@ public class BookmarkManager private ComponentName mOpenBookmarkComponentName; private ViewGroup mMainView; private BookmarkModel mBookmarkModel; + private ActivityWindowAndroid mWindowAndroid; ++ private ModalDialogManager mModalDialogManager; private BookmarkUndoController mUndoController; private final ObserverList mUIObservers = new ObserverList<>(); private BasicNativePage mNativePage; -@@ -328,6 +330,13 @@ public class BookmarkManager +@@ -328,6 +332,14 @@ public class BookmarkManager mNativePage = nativePage; } + /** + * Sets the Android window that is used by further intents created by the bookmark activity. + */ -+ public void setWindow(ActivityWindowAndroid window) { ++ public void setWindow(ActivityWindowAndroid window, ModalDialogManager modalDialogManager) { + mWindowAndroid = window; ++ mModalDialogManager = modalDialogManager; + } + /** * @return Current URL representing the UI state of bookmark manager. If no state has been shown * yet in this session, on phone return last used state stored in preference; on tablet -@@ -506,6 +515,16 @@ public class BookmarkManager +@@ -506,6 +518,16 @@ public class BookmarkManager } } @@ -336,7 +657,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm + + @Override + public void exportBookmarks() { -+ mBookmarkModel.exportBookmarks(mWindowAndroid); ++ mBookmarkModel.exportBookmarks(mWindowAndroid, mModalDialogManager); + } + @Override @@ -345,15 +666,17 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java -@@ -13,6 +13,7 @@ import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; +@@ -13,6 +13,9 @@ import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.native_page.BasicNativePage; import org.chromium.chrome.browser.ui.native_page.NativePageHost; import org.chromium.components.embedder_support.util.UrlConstants; +import org.chromium.chrome.browser.app.ChromeActivity; ++import org.chromium.ui.modaldialog.ModalDialogManager; ++import org.chromium.components.browser_ui.modaldialog.AppModalPresenter; /** * A native page holding a {@link BookmarkManager} on _tablet_. -@@ -29,11 +30,13 @@ public class BookmarkPage extends BasicNativePage { +@@ -29,11 +32,15 @@ public class BookmarkPage extends BasicNativePage { * @param host A NativePageHost to load urls. */ public BookmarkPage( @@ -364,7 +687,9 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm mManager = new BookmarkManager(host.getContext(), componentName, false, snackbarManager); mManager.setBasicNativePage(this); -+ mManager.setWindow(activity.getWindowAndroid()); ++ mManager.setWindow(activity.getWindowAndroid(), ++ new ModalDialogManager( ++ new AppModalPresenter(activity), ModalDialogManager.ModalDialogType.APP)); mTitle = host.getContext().getResources().getString(R.string.bookmarks); initWithView(mManager.getView()); @@ -411,6 +736,22 @@ diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn "browsing_data/access_context_audit_database.cc", "browsing_data/access_context_audit_database.h", "browsing_data/access_context_audit_service.cc", +diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc +--- a/chrome/browser/about_flags.cc ++++ b/chrome/browser/about_flags.cc +@@ -7115,6 +7115,12 @@ const FeatureEntry kFeatureEntries[] = { + FEATURE_VALUE_TYPE( + password_manager::features::kSyncingCompromisedCredentials)}, + ++ {"export-bookmarks-use-saf", ++ flag_descriptions::kBookmarksExportUseSafName, ++ flag_descriptions::kBookmarksExportUseSafDescription, kOsAndroid, ++ FEATURE_VALUE_TYPE( ++ chrome::android::kBookmarksExportUseSaf)}, ++ + // NOTE: Adding a new flag requires adding a corresponding entry to enum + // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag + // Histograms" in tools/metrics/histograms/README.md (run the diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc --- a/chrome/browser/android/bookmarks/bookmark_bridge.cc +++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc @@ -447,7 +788,7 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse using base::android::AttachCurrentThread; using base::android::ConvertUTF8ToJavaString; using base::android::ConvertUTF16ToJavaString; -@@ -64,6 +83,56 @@ using bookmarks::BookmarkNode; +@@ -64,8 +83,93 @@ using bookmarks::BookmarkNode; using bookmarks::BookmarkType; using content::BrowserThread; @@ -503,8 +844,45 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse + namespace { ++class FileBookmarksExportObserver: public BookmarksExportObserver { ++ public: ++ FileBookmarksExportObserver( ++ const JavaParamRef& obj, ++ ui::WindowAndroid* window, ++ const std::string& export_path) : ++ obj_(ScopedJavaGlobalRef(obj)), ++ window_(window), ++ export_path_(export_path) {} ++ ++ void OnExportFinished(Result result) override { ++ if (result == Result::kSuccess) { ++ LOG(INFO) << "Bookmarks exported successfully to " << export_path_; ++ } else if (result == Result::kCouldNotCreateFile) { ++ LOG(ERROR) << "Bookmarks export: could not create file " << export_path_; ++ } else if (result == Result::kCouldNotWriteHeader) { ++ LOG(ERROR) << "Bookmarks export: could not write header"; ++ } else if (result == Result::kCouldNotWriteNodes) { ++ LOG(ERROR) << "Bookmarks export: could not write nodes"; ++ } ++ ++ JNIEnv* env = AttachCurrentThread(); ++ Java_BookmarkBridge_bookmarksExported(env, obj_, window_->GetJavaObject(), ++ ConvertUTF8ToJavaString(env, export_path_), ++ result == Result::kSuccess); ++ delete this; ++ } ++ ++ private: ++ const ScopedJavaGlobalRef obj_; ++ ui::WindowAndroid* window_; ++ const std::string export_path_; ++}; ++ ++ const int kInvalidId = -1; -@@ -150,6 +219,10 @@ BookmarkBridge::~BookmarkBridge() { + + class BookmarkTitleComparer { +@@ -150,6 +254,10 @@ BookmarkBridge::~BookmarkBridge() { if (partner_bookmarks_shim_) partner_bookmarks_shim_->RemoveObserver(this); reading_list_manager_->RemoveObserver(this); @@ -515,7 +893,7 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse } void BookmarkBridge::Destroy(JNIEnv*, const JavaParamRef&) { -@@ -540,6 +613,175 @@ jint BookmarkBridge::GetTotalBookmarkCount( +@@ -540,6 +648,182 @@ jint BookmarkBridge::GetTotalBookmarkCount( return count; } @@ -554,10 +932,21 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse +} + +void BookmarkBridge::ExportBookmarks(JNIEnv* env, -+ const JavaParamRef& obj) { ++ const JavaParamRef& obj, ++ const JavaParamRef& java_window, ++ const JavaParamRef& j_export_path) { + DCHECK(IsLoaded()); + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + ++ ui::WindowAndroid* window = ++ ui::WindowAndroid::FromJavaWindowAndroid(java_window); ++ CHECK(window); ++ ++ base::string16 export_path = ++ base::android::ConvertJavaStringToUTF16(env, j_export_path); ++ ++ export_path_ = base::FilePath::FromUTF16Unsafe(export_path); ++ + if (export_path_.empty()) { + if (!base::android::GetDownloadsDirectory(&export_path_)) { + LOG(ERROR) << "Could not retrieve downloads directory for bookmarks export"; @@ -566,12 +955,8 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse + export_path_ = export_path_.Append(FILE_PATH_LITERAL("bookmarks.html")); + } + -+ bookmark_html_writer::WriteBookmarks(profile_, export_path_, NULL); -+ -+ Java_BookmarkBridge_bookmarksExported(env, obj, ConvertUTF8ToJavaString(env, export_path_.MaybeAsASCII())); -+ -+ //NOTE: nothing will be written if write permission has not been granted before -+ LOG(INFO) << "Bookmarks exported successfully to " << export_path_; ++ observer_ = new FileBookmarksExportObserver(obj, window, export_path_.MaybeAsASCII()); ++ bookmark_html_writer::WriteBookmarks(profile_, export_path_, observer_); +} + +// Attempts to create a TemplateURL from the provided data. |title| is optional. @@ -594,10 +979,10 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse + void* params) { + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()}, -+ base::BindOnce(&BookmarkBridge::FileSelectedImpl, ++ base::BindOnce(&BookmarkBridge::FileSelectedImpl, + base::Unretained(this), + path), -+ base::BindOnce(&BookmarkBridge::FileSelectedImplOnUIThread, ++ base::BindOnce(&BookmarkBridge::FileSelectedImplOnUIThread, + base::Unretained(this), + path)); +} @@ -694,7 +1079,15 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser/android/bookmarks/bookmark_bridge.h --- a/chrome/browser/android/bookmarks/bookmark_bridge.h +++ b/chrome/browser/android/bookmarks/bookmark_bridge.h -@@ -25,6 +25,9 @@ +@@ -17,6 +17,7 @@ + #include "base/strings/string16.h" + #include "base/strings/utf_string_conversions.h" + #include "chrome/browser/android/bookmarks/partner_bookmarks_shim.h" ++#include "chrome/browser/bookmarks/bookmark_html_writer.h" + #include "chrome/browser/profiles/profile.h" + #include "chrome/browser/profiles/profile_observer.h" + #include "chrome/browser/reading_list/android/reading_list_manager.h" +@@ -25,6 +26,9 @@ #include "components/prefs/pref_change_registrar.h" #include "url/android/gurl_android.h" @@ -704,7 +1097,7 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser namespace bookmarks { class BookmarkModel; class ManagedBookmarkService; -@@ -39,7 +42,8 @@ class Profile; +@@ -39,7 +43,8 @@ class Profile; class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, public PartnerBookmarksShim::Observer, public ReadingListManager::Observer, @@ -714,7 +1107,7 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser public: BookmarkBridge(JNIEnv* env, const base::android::JavaRef& obj, -@@ -55,6 +59,12 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, +@@ -55,6 +60,12 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, bool IsDoingExtensiveChanges(JNIEnv* env, const base::android::JavaParamRef& obj); @@ -727,7 +1120,7 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser jboolean IsEditBookmarksEnabled(JNIEnv* env); void LoadEmptyPartnerBookmarkShimForTesting( -@@ -142,6 +152,13 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, +@@ -142,6 +153,15 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, jlong id, jint type); @@ -736,16 +1129,19 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser + const base::android::JavaParamRef& java_window); + + void ExportBookmarks(JNIEnv* env, -+ const base::android::JavaParamRef& obj); ++ const base::android::JavaParamRef& obj, ++ const base::android::JavaParamRef& java_window, ++ const base::android::JavaParamRef& j_export_path); + void SetBookmarkTitle(JNIEnv* env, const base::android::JavaParamRef& obj, jlong id, -@@ -315,12 +332,14 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, +@@ -315,12 +335,15 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, void DestroyJavaObject(); Profile* profile_; + base::FilePath export_path_; ++ BookmarksExportObserver* observer_; // weak JavaObjectWeakGlobalRef weak_java_ref_; bookmarks::BookmarkModel* bookmark_model_; // weak bookmarks::ManagedBookmarkService* managed_bookmark_service_; // weak @@ -756,16 +1152,179 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser // Information about the Partner bookmarks (must check for IsLoaded()). // This is owned by profile. -@@ -332,6 +351,9 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, +@@ -332,6 +355,9 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, // Observes the profile destruction and creation. ScopedObserver profile_observer_{this}; + const std::string FileSelectedImpl(const base::FilePath& path); -+ void FileSelectedImplOnUIThread(const base::FilePath& path, ++ void FileSelectedImplOnUIThread(const base::FilePath& path, + const std::string& contents); DISALLOW_COPY_AND_ASSIGN(BookmarkBridge); }; +diff --git a/chrome/browser/bookmarks/bookmark_html_writer.cc b/chrome/browser/bookmarks/bookmark_html_writer.cc +--- a/chrome/browser/bookmarks/bookmark_html_writer.cc ++++ b/chrome/browser/bookmarks/bookmark_html_writer.cc +@@ -27,6 +27,7 @@ + #include "base/task/thread_pool.h" + #include "base/time/time.h" + #include "base/values.h" ++#include "base/android/content_uri_utils.h" + #include "chrome/browser/bookmarks/bookmark_model_factory.h" + #include "chrome/browser/favicon/favicon_service_factory.h" + #include "chrome/browser/profiles/profile.h" +@@ -240,7 +241,11 @@ class Writer : public base::RefCountedThreadSafe { + // Opens the file, returning true on success. + bool OpenFile() { + int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE; +- file_.reset(new base::File(path_, flags)); ++ if (path_.IsContentUri()) { ++ file_ = std::make_unique(base::OpenContentUriForWrite(path_)); ++ } else { ++ file_.reset(new base::File(path_, flags)); ++ } + if (!file_->IsValid()) { + PLOG(ERROR) << "Could not create " << path_; + return false; +diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationCustomView.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationCustomView.java +--- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationCustomView.java ++++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationCustomView.java +@@ -49,7 +49,7 @@ public class DownloadLocationCustomView + private TextView mFileSize; + private Spinner mFileLocation; + private TextView mLocationAvailableSpace; +- private CheckBox mDontShowAgain; ++ public CheckBox mDontShowAgain; + private @DownloadLocationDialogType int mDialogType; + private long mTotalBytes; + +@@ -71,6 +71,7 @@ public class DownloadLocationCustomView + mDontShowAgain = findViewById(R.id.show_again_checkbox); + } + ++ public + void initialize(@DownloadLocationDialogType int dialogType, File suggestedPath, long totalBytes, + CharSequence title) { + mDialogType = dialogType; +@@ -131,7 +132,7 @@ public class DownloadLocationCustomView + * @return The text that the user inputted as the name of the file. + */ + @Nullable +- String getFileName() { ++ public String getFileName() { + if (mFileName == null || mFileName.getText() == null) return null; + return mFileName.getText().toString(); + } +@@ -140,7 +141,7 @@ public class DownloadLocationCustomView + * @return The file path based on what the user selected as the location of the file. + */ + @Nullable +- DirectoryOption getDirectoryOption() { ++ public DirectoryOption getDirectoryOption() { + if (mFileLocation == null) return null; + DirectoryOption selected = (DirectoryOption) mFileLocation.getSelectedItem(); + return selected; +diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogCoordinator.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogCoordinator.java +--- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogCoordinator.java ++++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogCoordinator.java +@@ -34,13 +34,13 @@ import java.util.ArrayList; + public class DownloadLocationDialogCoordinator implements ModalDialogProperties.Controller { + @NonNull + private DownloadLocationDialogController mController; +- private PropertyModel mDialogModel; +- private DownloadLocationCustomView mCustomView; +- private ModalDialogManager mModalDialogManager; ++ protected PropertyModel mDialogModel; ++ protected DownloadLocationCustomView mCustomView; ++ protected ModalDialogManager mModalDialogManager; + private long mTotalBytes; + private @DownloadLocationDialogType int mDialogType; + private String mSuggestedPath; +- private Context mContext; ++ protected Context mContext; + + /** + * Initializes the download location dialog. +@@ -119,7 +119,7 @@ public class DownloadLocationDialogCoordinator implements ModalDialogProperties. + * Called after retrieved the download directory options. + * @param dirs An list of available download directories. + */ +- private void onDirectoryOptionsRetrieved(ArrayList dirs) { ++ protected void onDirectoryOptionsRetrieved(ArrayList dirs) { + // Already showing the dialog. + if (mDialogModel != null) return; + +diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc +--- a/chrome/browser/flag_descriptions.cc ++++ b/chrome/browser/flag_descriptions.cc +@@ -4988,6 +4988,11 @@ const char kWebrtcPipeWireCapturerDescription[] = + "capturing the desktop content on the Wayland display server."; + #endif // #if defined(WEBRTC_USE_PIPEWIRE) + ++const char kBookmarksExportUseSafName[] = "Use saf for bookmarks export"; ++const char kBookmarksExportUseSafDescription[] = ++ "When enabled user can choose where save the exported bookmarks " ++ "file."; ++ + // ============================================================================ + // Don't just add flags to the end, put them in the right section in + // alphabetical order just like the header file. +diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h +--- a/chrome/browser/flag_descriptions.h ++++ b/chrome/browser/flag_descriptions.h +@@ -2928,6 +2928,9 @@ extern const char kWebrtcPipeWireCapturerName[]; + extern const char kWebrtcPipeWireCapturerDescription[]; + #endif // #if defined(WEBRTC_USE_PIPEWIRE) + ++extern const char kBookmarksExportUseSafName[]; ++extern const char kBookmarksExportUseSafDescription[]; ++ + // ============================================================================ + // Don't just add flags to the end, put them in the right section in + // alphabetical order. See top instructions for more. +diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc +--- a/chrome/browser/flags/android/chrome_feature_list.cc ++++ b/chrome/browser/flags/android/chrome_feature_list.cc +@@ -138,6 +138,7 @@ const base::Feature* kFeaturesExposedToJava[] = { + &kAssistantIntentPageUrl, + &kAssistantIntentTranslateInfo, + &kBentoOffline, ++ &kBookmarksExportUseSaf, + &kCastDeviceFilter, + &kCloseTabSuggestions, + &kCriticalPersistedTabData, +@@ -724,6 +725,9 @@ const base::Feature kVoiceButtonInTopToolbar{"VoiceButtonInTopToolbar", + const base::Feature kVrBrowsingFeedback{"VrBrowsingFeedback", + base::FEATURE_ENABLED_BY_DEFAULT}; + ++const base::Feature kBookmarksExportUseSaf{"BookmarksExportUseSaf", ++ base::FEATURE_ENABLED_BY_DEFAULT}; ++ + static jboolean JNI_ChromeFeatureList_IsEnabled( + JNIEnv* env, + const JavaParamRef& jfeature_name) { +diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h +--- a/chrome/browser/flags/android/chrome_feature_list.h ++++ b/chrome/browser/flags/android/chrome_feature_list.h +@@ -151,6 +151,7 @@ extern const base::Feature kVoiceSearchAudioCapturePolicy; + extern const base::Feature kVoiceButtonInTopToolbar; + extern const base::Feature kVrBrowsingFeedback; + extern const base::Feature kPrefetchNotificationSchedulingIntegration; ++extern const base::Feature kBookmarksExportUseSaf; + + } // namespace android + } // namespace chrome +diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java ++++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +@@ -481,6 +481,7 @@ public abstract class ChromeFeatureList { + public static final String WEB_AUTH_PHONE_SUPPORT = "WebAuthenticationPhoneSupport"; + public static final String WEB_FEED = "WebFeed"; + public static final String XSURFACE_METRICS_REPORTING = "XsurfaceMetricsReporting"; ++ public static final String BOOKMARKS_EXPORT_USESAF = "BookmarksExportUseSaf"; + + @NativeMethods + interface Natives { diff --git a/chrome/browser/importer/profile_writer.cc b/chrome/browser/importer/profile_writer.cc --- a/chrome/browser/importer/profile_writer.cc +++ b/chrome/browser/importer/profile_writer.cc @@ -824,10 +1383,30 @@ diff --git a/chrome/browser/importer/profile_writer.h b/chrome/browser/importer/ virtual void AddFavicons(const favicon_base::FaviconUsageDataList& favicons); // Adds the TemplateURLs in |template_urls| to the local store. +diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java ++++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +@@ -90,6 +90,8 @@ public final class ChromePreferenceKeys { + public static final String BOOKMARKS_LAST_USED_URL = "enhanced_bookmark_last_used_url"; + public static final String BOOKMARKS_LAST_USED_PARENT = + "enhanced_bookmark_last_used_parent_folder"; ++ public static final String BOOKMARKS_LAST_EXPORT_URI = ++ "Chrome.Bookmarks.Last_Export_Uri"; + + /** + * Whether Chrome is set as the default browser. +@@ -845,6 +847,7 @@ public final class ChromePreferenceKeys { + AUTOFILL_ASSISTANT_NUMBER_OF_LITE_SCRIPTS_CANCELED, + AUTOFILL_ASSISTANT_PROACTIVE_HELP, + APPLICATION_OVERRIDE_LANGUAGE, ++ BOOKMARKS_LAST_EXPORT_URI, + CLIPBOARD_SHARED_URI, + CONDITIONAL_TAB_STRIP_CONTINUOUS_DISMISS_COUNTER, + CONDITIONAL_TAB_STRIP_FEATURE_STATUS, diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd -@@ -242,6 +242,12 @@ CHAR-LIMIT guidelines: +@@ -242,6 +242,24 @@ CHAR-LIMIT guidelines: Sites @@ -836,6 +1415,18 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro + + + Export ++ ++ ++ Export bookmarks to file ++ ++ ++ Do you want to overwrite %s? ++ ++ ++ Yes ++ ++ ++ Choose another file + Virtual Reality @@ -1054,6 +1645,19 @@ diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui /** * Checks whether the list of accepted types effectively describes only a single * type, which might be wildcard. For example: +diff --git a/ui/android/java/strings/android_ui_strings.grd b/ui/android/java/strings/android_ui_strings.grd +--- a/ui/android/java/strings/android_ui_strings.grd ++++ b/ui/android/java/strings/android_ui_strings.grd +@@ -174,6 +174,9 @@ + + Failed to open selected file + ++ ++ Failed to save selected file ++ + + + diff --git a/ui/shell_dialogs/select_file_dialog.h b/ui/shell_dialogs/select_file_dialog.h --- a/ui/shell_dialogs/select_file_dialog.h +++ b/ui/shell_dialogs/select_file_dialog.h diff --git a/build/patches/Add-custom-tab-intents-privacy-option.patch b/build/patches/Add-custom-tab-intents-privacy-option.patch index d1c3a929..29d54bfd 100644 --- a/build/patches/Add-custom-tab-intents-privacy-option.patch +++ b/build/patches/Add-custom-tab-intents-privacy-option.patch @@ -88,7 +88,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/setting diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd -@@ -3974,6 +3974,13 @@ Data from your Incognito session will only be cleared from Chrome when you Show original diff --git a/build/patches/Add-exit-menu-item.patch b/build/patches/Add-exit-menu-item.patch index e6f72d6d..9ca9be86 100644 --- a/build/patches/Add-exit-menu-item.patch +++ b/build/patches/Add-exit-menu-item.patch @@ -4,13 +4,13 @@ Subject: Add exit menu item Corrected Exit functionality --- - chrome/android/java/res/menu/main_menu.xml | 5 +++++ + chrome/android/java/res/menu/main_menu.xml | 6 ++++++ chrome/android/java/res/menu/main_menu_regroup.xml | 3 +++ .../org/chromium/chrome/browser/ChromeTabbedActivity.java | 3 +++ .../src/org/chromium/chrome/browser/app/ChromeActivity.java | 6 ++++++ .../chrome/browser/init/ChromeLifetimeController.java | 6 +++++- .../browser/ui/android/strings/android_chrome_strings.grd | 3 +++ - 6 files changed, 25 insertions(+), 1 deletion(-) + 6 files changed, 26 insertions(+), 1 deletion(-) diff --git a/chrome/android/java/res/menu/main_menu.xml b/chrome/android/java/res/menu/main_menu.xml --- a/chrome/android/java/res/menu/main_menu.xml @@ -25,12 +25,13 @@ diff --git a/chrome/android/java/res/menu/main_menu.xml b/chrome/android/java/re -@@ -145,6 +148,8 @@ +@@ -145,6 +148,9 @@ + ++ android:title="@string/menu_exit" ++ android:icon="@drawable/ic_exit_to_app_white_24dp" /> diff --git a/build/patches/Add-flag-for-save-data-header.patch b/build/patches/Add-flag-for-save-data-header.patch index b23a1e80..c1804eac 100644 --- a/build/patches/Add-flag-for-save-data-header.patch +++ b/build/patches/Add-flag-for-save-data-header.patch @@ -14,7 +14,7 @@ Subject: Add flag for save-data-header diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc -@@ -4326,6 +4326,9 @@ const FeatureEntry kFeatureEntries[] = { +@@ -4332,6 +4332,9 @@ const FeatureEntry kFeatureEntries[] = { #endif // BUILDFLAG(IS_CHROMEOS_ASH) #if defined(OS_ANDROID) diff --git a/build/patches/Add-history-support-in-incognito-mode.patch b/build/patches/Add-history-support-in-incognito-mode.patch index c8a88d81..ea9f5452 100644 --- a/build/patches/Add-history-support-in-incognito-mode.patch +++ b/build/patches/Add-history-support-in-incognito-mode.patch @@ -175,7 +175,7 @@ diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browse diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd -@@ -868,6 +868,12 @@ Your Google account may have other forms of browsing history like searches and a +@@ -880,6 +880,12 @@ Your Google account may have other forms of browsing history like searches and a Opens links in incognito tabs when you click on new tab or on a link diff --git a/build/patches/Add-menu-item-to-bookmark-all-tabs.patch b/build/patches/Add-menu-item-to-bookmark-all-tabs.patch index 02100081..9d1632a0 100644 --- a/build/patches/Add-menu-item-to-bookmark-all-tabs.patch +++ b/build/patches/Add-menu-item-to-bookmark-all-tabs.patch @@ -35,7 +35,7 @@ diff --git a/chrome/android/java/res/menu/main_menu.xml b/chrome/android/java/re -@@ -134,6 +138,9 @@ +@@ -133,6 +137,9 @@ @@ -120,7 +120,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm import android.content.Intent; import android.content.Context; import android.content.pm.PackageManager; -@@ -18,6 +19,7 @@ import androidx.annotation.Nullable; +@@ -24,6 +25,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.base.ContextUtils; @@ -128,7 +128,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm import org.chromium.base.ObserverList; import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; -@@ -26,6 +28,10 @@ import org.chromium.base.metrics.RecordHistogram; +@@ -32,6 +34,10 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; @@ -139,7 +139,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm import org.chromium.components.bookmarks.BookmarkId; import org.chromium.components.bookmarks.BookmarkType; import org.chromium.components.url_formatter.SchemeDisplay; -@@ -46,6 +52,7 @@ import java.util.List; +@@ -72,6 +78,7 @@ import java.io.File; * bookmark model stored in native. */ public class BookmarkBridge { @@ -147,7 +147,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm private final Profile mProfile; private boolean mIsDoingExtensiveChanges; private long mNativeBookmarkBridge; -@@ -527,6 +534,16 @@ public class BookmarkBridge { +@@ -553,6 +560,16 @@ public class BookmarkBridge { mNativeBookmarkBridge, BookmarkBridge.this); } @@ -164,7 +164,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm /** * @return Id representing the special "other" folder from bookmark model. */ -@@ -896,6 +913,50 @@ public class BookmarkBridge { +@@ -1094,6 +1111,50 @@ public class BookmarkBridge { mNativeBookmarkBridge, BookmarkBridge.this, title, url); } @@ -215,7 +215,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm /** * @param url The URL of the reading list item. * @return The reading list item with the URL, or null if no such reading list item. -@@ -1137,6 +1198,7 @@ public class BookmarkBridge { +@@ -1350,6 +1411,7 @@ public class BookmarkBridge { void getAllFoldersWithDepths(long nativeBookmarkBridge, BookmarkBridge caller, List folderList, List depthList); BookmarkId getRootFolderId(long nativeBookmarkBridge, BookmarkBridge caller); @@ -247,7 +247,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/Bookm diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc --- a/chrome/browser/android/bookmarks/bookmark_bridge.cc +++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc -@@ -387,6 +387,11 @@ void BookmarkBridge::GetTopLevelFolderIDs( +@@ -422,6 +422,11 @@ void BookmarkBridge::GetTopLevelFolderIDs( top_level_folders.push_back(node.get()); } @@ -259,7 +259,7 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse for (const auto& node : bookmark_model_->bookmark_bar_node()->children()) { if (node->is_folder()) top_level_folders.push_back(node.get()); -@@ -425,6 +430,7 @@ void BookmarkBridge::GetAllFoldersWithDepths( +@@ -460,6 +465,7 @@ void BookmarkBridge::GetAllFoldersWithDepths( // Vector to temporarily contain all child bookmarks at same level for sorting std::vector bookmarks = { bookmark_model_->mobile_node(), @@ -267,7 +267,7 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse bookmark_model_->bookmark_bar_node(), bookmark_model_->other_node(), }; -@@ -479,6 +485,17 @@ ScopedJavaLocalRef BookmarkBridge::GetMobileFolderId( +@@ -514,6 +520,17 @@ ScopedJavaLocalRef BookmarkBridge::GetMobileFolderId( return folder_id_obj; } @@ -288,7 +288,7 @@ diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browse diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser/android/bookmarks/bookmark_bridge.h --- a/chrome/browser/android/bookmarks/bookmark_bridge.h +++ b/chrome/browser/android/bookmarks/bookmark_bridge.h -@@ -109,6 +109,10 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, +@@ -110,6 +110,10 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, JNIEnv* env, const base::android::JavaParamRef& obj); @@ -314,7 +314,7 @@ diff --git a/chrome/browser/bookmarks/chrome_bookmark_client.cc b/chrome/browser diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd -@@ -3002,6 +3002,9 @@ Data from your Incognito session will only be cleared from Chrome when you Track prices diff --git a/build/patches/Add-menu-item-to-view-source.patch b/build/patches/Add-menu-item-to-view-source.patch index 0ba7f86d..00a4b1c8 100644 --- a/build/patches/Add-menu-item-to-view-source.patch +++ b/build/patches/Add-menu-item-to-view-source.patch @@ -121,7 +121,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/Cust diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd -@@ -332,6 +332,9 @@ CHAR-LIMIT guidelines: +@@ -344,6 +344,9 @@ CHAR-LIMIT guidelines: Other Google services diff --git a/build/patches/Add-option-to-force-tablet-UI.patch b/build/patches/Add-option-to-force-tablet-UI.patch index 7854dab9..7beea0ae 100644 --- a/build/patches/Add-option-to-force-tablet-UI.patch +++ b/build/patches/Add-option-to-force-tablet-UI.patch @@ -78,7 +78,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/Too diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java -@@ -442,6 +442,7 @@ public final class ChromePreferenceKeys { +@@ -444,6 +444,7 @@ public final class ChromePreferenceKeys { public static final String FONT_USER_SET_FORCE_ENABLE_ZOOM = "user_set_force_enable_zoom"; public static final String HISTORY_SHOW_HISTORY_INFO = "history_home_show_info"; @@ -100,7 +100,7 @@ diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/bro diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd -@@ -1152,6 +1152,12 @@ Your Google account may have other forms of browsing history like searches and a +@@ -1164,6 +1164,12 @@ Your Google account may have other forms of browsing history like searches and a Turn off diff --git a/build/patches/Add-option-to-not-persist-tabs-across-sessions.patch b/build/patches/Add-option-to-not-persist-tabs-across-sessions.patch index c3bf1017..df0be688 100644 --- a/build/patches/Add-option-to-not-persist-tabs-across-sessions.patch +++ b/build/patches/Add-option-to-not-persist-tabs-across-sessions.patch @@ -99,7 +99,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/setting diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd -@@ -3724,6 +3724,12 @@ Data from your Incognito session will only be cleared from Chrome when you IMAGE diff --git a/build/patches/Automated-domain-substitution.patch b/build/patches/Automated-domain-substitution.patch index eaead174..98f76b2d 100644 --- a/build/patches/Automated-domain-substitution.patch +++ b/build/patches/Automated-domain-substitution.patch @@ -4172,7 +4172,7 @@ diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc const FeatureEntry::Choice kPassiveListenersChoices[] = { {flags_ui::kGenericExperimentChoiceDefault, "", ""}, -@@ -3504,7 +3504,7 @@ const FeatureEntry kFeatureEntries[] = { +@@ -3510,7 +3510,7 @@ const FeatureEntry kFeatureEntries[] = { flag_descriptions::kSyncSandboxDescription, kOsAll, SINGLE_VALUE_TYPE_AND_VALUE( switches::kSyncServiceURL, @@ -4181,7 +4181,7 @@ diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc #if !defined(OS_ANDROID) {"load-media-router-component-extension", flag_descriptions::kLoadMediaRouterComponentExtensionName, -@@ -3750,7 +3750,7 @@ const FeatureEntry kFeatureEntries[] = { +@@ -3756,7 +3756,7 @@ const FeatureEntry kFeatureEntries[] = { flag_descriptions::kSetMarketUrlForTestingName, flag_descriptions::kSetMarketUrlForTestingDescription, kOsAndroid, SINGLE_VALUE_TYPE_AND_VALUE(switches::kMarketUrlForTesting, @@ -7984,7 +7984,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro CHAR-LIMIT guidelines: Certain strings need character limits to prevent a long translation from breaking the UI. -@@ -846,7 +846,7 @@ For example, some websites may respond to this request by showing you ads that a +@@ -858,7 +858,7 @@ For example, some websites may respond to this request by showing you ads that a Choose another provider @@ -7993,7 +7993,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro This setting is disabled on managed browsers -@@ -876,7 +876,7 @@ For example, some websites may respond to this request by showing you ads that a +@@ -888,7 +888,7 @@ For example, some websites may respond to this request by showing you ads that a The selected data has been removed from Chrome and your synced devices. @@ -8002,7 +8002,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro Cached images and files -@@ -910,10 +910,10 @@ Your Google account may have other forms of browsing history like searches and a +@@ -922,10 +922,10 @@ Your Google account may have other forms of browsing history like searches and a Record history even in incognito mode @@ -8015,7 +8015,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro Saved passwords -@@ -973,7 +973,7 @@ Your Google account may have other forms of browsing history like searches and a +@@ -985,7 +985,7 @@ Your Google account may have other forms of browsing history like searches and a Basic @@ -8024,7 +8024,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro Blocked site -@@ -1359,7 +1359,7 @@ Your Google account may have other forms of browsing history like searches and a +@@ -1371,7 +1371,7 @@ Your Google account may have other forms of browsing history like searches and a In Lite mode, Chrome loads pages faster and uses up to 60 percent less data. To optimize the pages that you visit, Chrome sends your web traffic to Google. <link>Learn more</link> @@ -8033,7 +8033,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro Turn on Lite mode -@@ -1528,10 +1528,10 @@ Your Google account may have other forms of browsing history like searches and a +@@ -1540,10 +1540,10 @@ Your Google account may have other forms of browsing history like searches and a Waiting for details of parents. @@ -8046,7 +8046,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro Content -@@ -1590,22 +1590,22 @@ Your Google account may have other forms of browsing history like searches and a +@@ -1602,22 +1602,22 @@ Your Google account may have other forms of browsing history like searches and a Google Terms of Service @@ -8073,7 +8073,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro -@@ -1622,7 +1622,7 @@ Your Google account may have other forms of browsing history like searches and a +@@ -1634,7 +1634,7 @@ Your Google account may have other forms of browsing history like searches and a Also clear your Chrome data from this device @@ -8082,7 +8082,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro Contacting Google. This may take a minute… -@@ -1770,7 +1770,7 @@ To change this setting, <resetlink>reset sync

<resetlink>reset sync

@@ -8091,7 +8091,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro <link>Get help</link> while scanning for devices… -@@ -1815,7 +1815,7 @@ To change this setting, <resetlink>reset sync

<resetlink>reset sync

@@ -8100,7 +8100,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro Unknown or unsupported device (%1$sA1:B2:C3:D4:E5:F6) -@@ -2280,7 +2280,7 @@ To change this setting, <resetlink>reset sync

<resetlink>reset sync

@@ -8109,7 +8109,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro You are viewing a preview of this page -@@ -3599,7 +3599,7 @@ Data from your Incognito session will only be cleared from Chrome when you @@ -8118,7 +8118,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro No compatible devices found -@@ -3638,7 +3638,7 @@ Data from your Incognito session will only be cleared from Chrome when you @@ -8127,7 +8127,7 @@ diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chro Got it -@@ -3893,7 +3893,7 @@ Data from your Incognito session will only be cleared from Chrome when you %1$sTanya's Pixel 2... diff --git a/build/patches/Disable-smart-selection-by-default.patch b/build/patches/Disable-smart-selection-by-default.patch index 29e64f0b..0076442a 100644 --- a/build/patches/Disable-smart-selection-by-default.patch +++ b/build/patches/Disable-smart-selection-by-default.patch @@ -15,7 +15,7 @@ leak information through the TextClassifier set by OEM, if any diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc -@@ -502,7 +502,7 @@ const base::Feature kDownloadProgressInfoBar{"DownloadProgressInfoBar", +@@ -503,7 +503,7 @@ const base::Feature kDownloadProgressInfoBar{"DownloadProgressInfoBar", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kDownloadFileProvider{"DownloadFileProvider", diff --git a/build/patches/Disable-text-fragments-by-default.patch b/build/patches/Disable-text-fragments-by-default.patch index 10267e9f..b5d5093f 100644 --- a/build/patches/Disable-text-fragments-by-default.patch +++ b/build/patches/Disable-text-fragments-by-default.patch @@ -17,7 +17,7 @@ Revert "[Text Fragment] Unflag fragment directive removal." diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc -@@ -5164,6 +5164,7 @@ const FeatureEntry kFeatureEntries[] = { +@@ -5170,6 +5170,7 @@ const FeatureEntry kFeatureEntries[] = { kHappinessTrackingSurveysForDesktopDevToolsIssuesCookiesSameSiteDescription, kOsDesktop, FEATURE_VALUE_TYPE( diff --git a/build/patches/Enable-app-overflow-menu-icons-by-default.patch b/build/patches/Enable-app-overflow-menu-icons-by-default.patch index 1ffb638b..b64a286b 100644 --- a/build/patches/Enable-app-overflow-menu-icons-by-default.patch +++ b/build/patches/Enable-app-overflow-menu-icons-by-default.patch @@ -9,7 +9,7 @@ Subject: Enable app overflow menu icons by default diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc -@@ -647,7 +647,7 @@ const base::Feature kTabToGTSAnimation{"TabToGTSAnimation", +@@ -648,7 +648,7 @@ const base::Feature kTabToGTSAnimation{"TabToGTSAnimation", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kTabbedAppOverflowMenuIcons{ diff --git a/build/patches/Enable-darken-websites-checkbox-in-themes.patch b/build/patches/Enable-darken-websites-checkbox-in-themes.patch index 3f477b1b..ab1dd75c 100644 --- a/build/patches/Enable-darken-websites-checkbox-in-themes.patch +++ b/build/patches/Enable-darken-websites-checkbox-in-themes.patch @@ -23,7 +23,7 @@ diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.js diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc -@@ -490,7 +490,7 @@ const base::Feature kContextualSearchTranslations{ +@@ -491,7 +491,7 @@ const base::Feature kContextualSearchTranslations{ "ContextualSearchTranslations", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kDarkenWebsitesCheckboxInThemesSetting{ diff --git a/build/patches/Remove-help-menu-item.patch b/build/patches/Remove-help-menu-item.patch index 4357acd3..89cd5b0c 100644 --- a/build/patches/Remove-help-menu-item.patch +++ b/build/patches/Remove-help-menu-item.patch @@ -3,25 +3,26 @@ Date: Wed, 27 Jun 2018 01:32:28 +0200 Subject: Remove help menu item --- - chrome/android/java/res/menu/main_menu.xml | 2 -- + chrome/android/java/res/menu/main_menu.xml | 3 --- .../org/chromium/chrome/browser/KeyboardShortcuts.java | 3 --- .../org/chromium/chrome/browser/app/ChromeActivity.java | 9 --------- .../chrome/browser/customtabs/BaseCustomTabActivity.java | 2 +- .../browser/directactions/MenuDirectActionHandler.java | 2 -- - 5 files changed, 1 insertion(+), 17 deletions(-) + 5 files changed, 1 insertion(+), 18 deletions(-) diff --git a/chrome/android/java/res/menu/main_menu.xml b/chrome/android/java/res/menu/main_menu.xml --- a/chrome/android/java/res/menu/main_menu.xml +++ b/chrome/android/java/res/menu/main_menu.xml -@@ -111,8 +111,6 @@ +@@ -111,9 +111,6 @@ - +- android:icon="@drawable/help_outline" /> diff --git a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java --- a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java diff --git a/build/patches/Restore-Search-Ready-Omnibox-flag.patch b/build/patches/Restore-Search-Ready-Omnibox-flag.patch index f5f5ea2d..eaf92cce 100644 --- a/build/patches/Restore-Search-Ready-Omnibox-flag.patch +++ b/build/patches/Restore-Search-Ready-Omnibox-flag.patch @@ -110,7 +110,7 @@ diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptio diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc -@@ -206,6 +206,7 @@ const base::Feature* kFeaturesExposedToJava[] = { +@@ -207,6 +207,7 @@ const base::Feature* kFeaturesExposedToJava[] = { &kReachedCodeProfiler, &kReaderModeInCCT, &kReengagementNotification, @@ -118,7 +118,7 @@ diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browse &kRelatedSearches, &kSearchEnginePromoExistingDevice, &kSearchEnginePromoNewDevice, -@@ -586,6 +587,9 @@ const base::Feature kReengagementNotification{ +@@ -587,6 +588,9 @@ const base::Feature kReengagementNotification{ const base::Feature kRelatedSearches{"RelatedSearches", base::FEATURE_DISABLED_BY_DEFAULT}; diff --git a/build/patches/Restore-Simplified-NTP-launch.patch b/build/patches/Restore-Simplified-NTP-launch.patch index d995008e..aff13ea2 100644 --- a/build/patches/Restore-Simplified-NTP-launch.patch +++ b/build/patches/Restore-Simplified-NTP-launch.patch @@ -306,7 +306,7 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Sug diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc -@@ -3728,6 +3728,9 @@ const FeatureEntry kFeatureEntries[] = { +@@ -3734,6 +3734,9 @@ const FeatureEntry kFeatureEntries[] = { SINGLE_VALUE_TYPE_AND_VALUE( switches::kForceShowUpdateMenuItemCustomSummary, "Custom Summary")}, @@ -345,7 +345,7 @@ diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptio diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc -@@ -187,6 +187,7 @@ const base::Feature* kFeaturesExposedToJava[] = { +@@ -188,6 +188,7 @@ const base::Feature* kFeaturesExposedToJava[] = { &kEnhancedProtectionPromoCard, &kEphemeralTabUsingBottomSheet, &kExploreSites, @@ -353,7 +353,7 @@ diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browse &kFocusOmniboxInIncognitoTabIntents, &kGPayAppDynamicUpdate, &kHandleMediaIntents, -@@ -566,6 +567,9 @@ const base::Feature kOfflineIndicatorV2{"OfflineIndicatorV2", +@@ -567,6 +568,9 @@ const base::Feature kOfflineIndicatorV2{"OfflineIndicatorV2", const base::Feature kOfflineMeasurementsBackgroundTask{ "OfflineMeasurementsBackgroundTask", base::FEATURE_DISABLED_BY_DEFAULT}; diff --git a/build/patches/Revert-flags-remove-num-raster-threads.patch b/build/patches/Revert-flags-remove-num-raster-threads.patch index bba31291..21540803 100644 --- a/build/patches/Revert-flags-remove-num-raster-threads.patch +++ b/build/patches/Revert-flags-remove-num-raster-threads.patch @@ -29,7 +29,7 @@ diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc const FeatureEntry::Choice kTouchTextSelectionStrategyChoices[] = { {flags_ui::kGenericExperimentChoiceDefault, "", ""}, {flag_descriptions::kTouchSelectionStrategyCharacter, -@@ -3295,6 +3304,9 @@ const FeatureEntry kFeatureEntries[] = { +@@ -3301,6 +3310,9 @@ const FeatureEntry kFeatureEntries[] = { feature_engagement::kIPHDemoMode, feature_engagement::kIPHDemoModeChoiceVariations, "IPH_DemoMode")}, diff --git a/build/patches/User-agent-customization.patch b/build/patches/User-agent-customization.patch index 56d63b91..551d47f4 100644 --- a/build/patches/User-agent-customization.patch +++ b/build/patches/User-agent-customization.patch @@ -961,7 +961,7 @@ diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/ch diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java -@@ -826,6 +826,9 @@ public final class ChromePreferenceKeys { +@@ -828,6 +828,9 @@ public final class ChromePreferenceKeys { public static final KeyPrefix KEY_ZERO_SUGGEST_HEADER_GROUP_COLLAPSED_BY_DEFAULT_PREFIX = new KeyPrefix("zero_suggest_header_group_collapsed_by_default*"); @@ -971,7 +971,7 @@ diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/bro /** * These values are currently used as SharedPreferences keys, along with the keys in * {@link GrandfatheredChromePreferenceKeys#getKeysInUse()}. Add new SharedPreferences keys -@@ -887,7 +890,9 @@ public final class ChromePreferenceKeys { +@@ -890,7 +893,9 @@ public final class ChromePreferenceKeys { SETTINGS_SAFETY_CHECK_RUN_COUNTER, SIGNIN_PROMO_IMPRESSIONS_COUNT_NTP, TWA_DISCLOSURE_SEEN_PACKAGES,