diff --git a/build/bromite_patches_list.txt b/build/bromite_patches_list.txt index fe278ced..0b238487 100644 --- a/build/bromite_patches_list.txt +++ b/build/bromite_patches_list.txt @@ -34,7 +34,6 @@ Skip-the-first-run-and-metrics.patch Disable-all-promo-dialogs.patch Remove-signin-and-data-saver-integrations.patch Hide-passwords-manager-link.patch -Disable-Omaha-update-checks.patch Disable-update-scheduler.patch Add-English-only-search-engine.patch Add-DuckDuckGo-Lite-search-engine.patch @@ -164,4 +163,5 @@ Enable-share-intent.patch Automated-domain-substitution.patch Observe-WebContents-in-PPAPIDownloadRequest.patch Prevents-non-browser-processes-from-requesting-memory-dumps.patch -Add-images-contentsettings.patch \ No newline at end of file +Add-images-contentsettings.patch +Enable-update-notification.patch diff --git a/build/patches/Enable-update-notification.patch b/build/patches/Enable-update-notification.patch new file mode 100644 index 00000000..3109cc21 --- /dev/null +++ b/build/patches/Enable-update-notification.patch @@ -0,0 +1,936 @@ +From: uazo +Date: Thu, 7 Oct 2021 14:27:12 +0000 +Subject: Enable update notification + +Enable checking for new version, with proxy support +--- + .../java/templates/BuildConfig.template | 2 + + build/config/android/rules.gni | 3 + + chrome/android/chrome_java_sources.gni | 1 + + .../java/res/xml/about_chrome_preferences.xml | 5 + + .../about_settings/AboutChromeSettings.java | 27 ++- + .../chrome/browser/omaha/OmahaBase.java | 44 +++- + .../chrome/browser/omaha/UpdateConfigs.java | 6 +- + .../browser/omaha/UpdateStatusProvider.java | 36 ++-- + .../browser/omaha/VersionNumberGetter.java | 3 +- + .../inline/BromiteInlineUpdateController.java | 204 ++++++++++++++++++ + .../inline/InlineUpdateControllerFactory.java | 8 +- + chrome/browser/endpoint_fetcher/BUILD.gn | 2 + + .../endpoint_fetcher/endpoint_fetcher.cc | 125 +++++++++++ + .../endpoint_fetcher/endpoint_fetcher.h | 23 +- + .../endpoint_fetcher/EndpointFetcher.java | 11 + + .../EndpointHeaderResponse.java | 31 +++ + chrome/browser/flag-metadata.json | 2 +- + chrome/browser/flag_descriptions.cc | 5 +- + .../flags/android/chrome_feature_list.cc | 2 +- + .../strings/android_chrome_strings.grd | 8 +- + 20 files changed, 511 insertions(+), 37 deletions(-) + create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/BromiteInlineUpdateController.java + create mode 100644 chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointHeaderResponse.java + +diff --git a/build/android/java/templates/BuildConfig.template b/build/android/java/templates/BuildConfig.template +--- a/build/android/java/templates/BuildConfig.template ++++ b/build/android/java/templates/BuildConfig.template +@@ -92,4 +92,6 @@ public class BuildConfig { + #else + public static MAYBE_FINAL boolean ISOLATED_SPLITS_ENABLED MAYBE_FALSE; + #endif ++ ++ public static MAYBE_FINAL String BUILD_TARGET_CPU = _BUILD_TARGET_CPU; + } +diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni +--- a/build/config/android/rules.gni ++++ b/build/config/android/rules.gni +@@ -1967,6 +1967,9 @@ if (enable_java_templates) { + ] + } + } ++ ++ # add arch to org.chromium.build.BuildConfig ++ defines += [ "_BUILD_TARGET_CPU=\"${target_cpu}\"" ] + } + } + +diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni +--- a/chrome/android/chrome_java_sources.gni ++++ b/chrome/android/chrome_java_sources.gni +@@ -880,6 +880,7 @@ chrome_java_sources = [ + "java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateController.java", + "java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java", + "java/src/org/chromium/chrome/browser/omaha/inline/NoopInlineUpdateController.java", ++ "java/src/org/chromium/chrome/browser/omaha/inline/BromiteInlineUpdateController.java", + "java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java", + "java/src/org/chromium/chrome/browser/omaha/metrics/HistogramUtils.java", + "java/src/org/chromium/chrome/browser/omaha/metrics/TrackingProvider.java", +diff --git a/chrome/android/java/res/xml/about_chrome_preferences.xml b/chrome/android/java/res/xml/about_chrome_preferences.xml +--- a/chrome/android/java/res/xml/about_chrome_preferences.xml ++++ b/chrome/android/java/res/xml/about_chrome_preferences.xml +@@ -7,6 +7,11 @@ + ++ + +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/AboutChromeSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/AboutChromeSettings.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/AboutChromeSettings.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/AboutChromeSettings.java +@@ -21,11 +21,16 @@ import org.chromium.ui.widget.Toast; + + import java.util.Calendar; + ++import android.content.SharedPreferences; ++import org.chromium.chrome.browser.omaha.OmahaBase; ++import org.chromium.components.browser_ui.settings.ChromeSwitchPreference; ++ + /** + * Settings fragment that displays information about Chrome. + */ + public class AboutChromeSettings +- extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener { ++ extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener, ++ Preference.OnPreferenceChangeListener { + private static final int TAPS_FOR_DEVELOPER_SETTINGS = 7; + + private static final String PREF_APPLICATION_VERSION = "application_version"; +@@ -59,6 +64,13 @@ public class AboutChromeSettings + p = findPreference(PREF_LEGAL_INFORMATION); + int currentYear = Calendar.getInstance().get(Calendar.YEAR); + p.setSummary(getString(R.string.legal_information_summary, currentYear)); ++ ++ ChromeSwitchPreference allowInlineUpdate = ++ (ChromeSwitchPreference) findPreference(OmahaBase.PREF_ALLOW_INLINE_UPDATE); ++ allowInlineUpdate.setChecked( ++ OmahaBase.getSharedPreferences() ++ .getBoolean(OmahaBase.PREF_ALLOW_INLINE_UPDATE, false)); ++ allowInlineUpdate.setOnPreferenceChangeListener(this); + } + + /** +@@ -122,4 +134,17 @@ public class AboutChromeSettings + } + return true; + } ++ ++ @Override ++ public boolean onPreferenceChange(Preference preference, Object newValue) { ++ String key = preference.getKey(); ++ if (OmahaBase.PREF_ALLOW_INLINE_UPDATE.equals(key)) { ++ SharedPreferences.Editor sharedPreferenceEditor = OmahaBase.getSharedPreferences().edit(); ++ sharedPreferenceEditor.putBoolean(OmahaBase.PREF_ALLOW_INLINE_UPDATE, (boolean) newValue); ++ sharedPreferenceEditor.apply(); ++ ++ OmahaBase.resetUpdatePrefs(); ++ } ++ return true; ++ } + } +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java +@@ -31,6 +31,8 @@ import java.net.HttpURLConnection; + import java.net.URL; + import java.util.Date; + ++import org.chromium.build.BuildConfig; ++ + /** + * Keeps tabs on the current state of Chrome, tracking if and when a request should be sent to the + * Omaha Server. +@@ -97,7 +99,9 @@ public class OmahaBase { + static final String PREF_TIMESTAMP_FOR_NEW_REQUEST = "timestampForNewRequest"; + static final String PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT = "timestampForNextPostAttempt"; + static final String PREF_TIMESTAMP_OF_INSTALL = "timestampOfInstall"; +- static final String PREF_TIMESTAMP_OF_REQUEST = "timestampOfRequest"; ++ public static final String PREF_TIMESTAMP_OF_REQUEST = "timestampOfRequest"; ++ public static final String PREF_LATEST_MODIFIED_VERSION = "latestModifiedVersion"; ++ public static final String PREF_ALLOW_INLINE_UPDATE = "allow_inline_update"; + + static final int MIN_API_JOB_SCHEDULER = Build.VERSION_CODES.M; + +@@ -157,8 +161,9 @@ public class OmahaBase { + } + + /** See {@link #sIsDisabled}. */ ++ // do not enable version control with Omaha Update Server + static boolean isDisabled() { +- return sIsDisabled; ++ return true; + } + + /** +@@ -630,4 +635,39 @@ public class OmahaBase { + // updateStatus is only used for the on-demand check. + null); + } ++ ++ public static boolean isNewVersionAvailableByVersion(String latestVersionString) { ++ VersionNumber mCurrentProductVersion = VersionNumber.fromString(ChromeVersionInfo.getProductVersion()); ++ if (mCurrentProductVersion == null || latestVersionString == null) ++ return false; ++ ++ VersionNumber latestVersion = VersionNumber.fromString(latestVersionString); ++ if (latestVersion == null) return false; ++ ++ Log.i(TAG, "isNewVersionAvailable: CurrentProductVersion: %s", ++ mCurrentProductVersion.toString()); ++ Log.i(TAG, "isNewVersionAvailable: LatestVersion: %s", ++ latestVersion.toString()); ++ ++ return mCurrentProductVersion.isSmallerThan(latestVersion); ++ } ++ ++ public static void updateLastPushedTimeStamp(long timeMillis) { ++ SharedPreferences preferences = OmahaBase.getSharedPreferences(); ++ SharedPreferences.Editor editor = preferences.edit(); ++ editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeMillis); ++ editor.apply(); ++ } ++ ++ public static void setLastModifiedVersion(String version) { ++ SharedPreferences preferences = OmahaBase.getSharedPreferences(); ++ SharedPreferences.Editor editor = preferences.edit(); ++ editor.putString(OmahaBase.PREF_LATEST_MODIFIED_VERSION, version); ++ editor.apply(); ++ } ++ ++ public static void resetUpdatePrefs() { ++ OmahaBase.setLastModifiedVersion(""); ++ OmahaBase.updateLastPushedTimeStamp(0); ++ } + } +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java +@@ -65,7 +65,7 @@ public class UpdateConfigs { + private static final String UPDATE_NOTIFICATION_EXPERIMENTAL_PARAM_NAME = + "update_notification_experimental_context"; + +- private static final long DEFAULT_UPDATE_NOTIFICATION_INTERVAL = 21 * DateUtils.DAY_IN_MILLIS; ++ private static final long DEFAULT_UPDATE_NOTIFICATION_INTERVAL = 7 * DateUtils.DAY_IN_MILLIS; + private static final long DEFAULT_UPDATE_ATTRIBUTION_WINDOW_MS = 2 * DateUtils.DAY_IN_MILLIS; + + /** Possible update flow configurations. */ +@@ -300,7 +300,7 @@ public class UpdateConfigs { + * @return the current inline update flow configuration. + */ + @UpdateFlowConfiguration +- static int getConfiguration() { ++ public static int getConfiguration() { + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.INLINE_UPDATE_FLOW)) { + // Always use the the old flow if the inline update flow feature is not enabled. + return UpdateFlowConfiguration.INTENT_ONLY; +@@ -328,4 +328,4 @@ public class UpdateConfigs { + if (configuration == null) return ""; + return configuration.toLowerCase(Locale.US); + } +-} +\ No newline at end of file ++} +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java +@@ -45,6 +45,12 @@ import java.io.File; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + ++import org.chromium.base.Log; ++import android.content.SharedPreferences; ++import android.os.Build; ++import org.chromium.build.BuildConfig; ++import org.chromium.chrome.browser.version.ChromeVersionInfo; ++ + /** + * Provides the current update state for Chrome. This update state is asynchronously determined and + * can change as Chrome runs. +@@ -112,6 +118,8 @@ public class UpdateStatusProvider implements ActivityStateListener { + */ + public String latestUnsupportedVersion; + ++ public long latestLastModifiedBuildTime; ++ + /** + * Whether or not we are currently trying to simulate the update. Used to ignore other + * update signals. +@@ -133,6 +141,7 @@ public class UpdateStatusProvider implements ActivityStateListener { + latestUnsupportedVersion = other.latestUnsupportedVersion; + mIsSimulated = other.mIsSimulated; + mIsInlineSimulated = other.mIsInlineSimulated; ++ latestLastModifiedBuildTime = other.latestLastModifiedBuildTime; + } + } + +@@ -339,8 +348,7 @@ public class UpdateStatusProvider implements ActivityStateListener { + case UpdateConfigs.UpdateFlowConfiguration.NEVER_SHOW: + return UpdateState.NONE; + case UpdateConfigs.UpdateFlowConfiguration.INLINE_ONLY: +- if (omahaState != UpdateState.UPDATE_AVAILABLE) return omahaState; +- if (inlineState == UpdateState.NONE) return UpdateState.NONE; ++ if (inlineState == UpdateState.NONE) return omahaState; + return inlineState; + case UpdateConfigs.UpdateFlowConfiguration.BEST_EFFORT: + if (omahaState != UpdateState.UPDATE_AVAILABLE) return omahaState; +@@ -415,24 +423,12 @@ public class UpdateStatusProvider implements ActivityStateListener { + private UpdateStatus getRealStatus(Context context) { + UpdateStatus status = new UpdateStatus(); + +- if (VersionNumberGetter.isNewerVersionAvailable(context)) { +- status.updateUrl = MarketURLGetter.getMarketUrl(); +- status.latestVersion = +- VersionNumberGetter.getInstance().getLatestKnownVersion(context); +- +- boolean allowedToUpdate = +- checkForSufficientStorage() && isGooglePlayStoreAvailable(context); +- status.updateState = +- allowedToUpdate ? UpdateState.UPDATE_AVAILABLE : UpdateState.NONE; +- +- SharedPreferencesManager.getInstance().removeKey( +- ChromePreferenceKeys.LATEST_UNSUPPORTED_VERSION); +- } else if (!VersionNumberGetter.isCurrentOsVersionSupported()) { +- status.updateState = UpdateState.UNSUPPORTED_OS_VERSION; +- status.latestUnsupportedVersion = SharedPreferencesManager.getInstance().readString( +- ChromePreferenceKeys.LATEST_UNSUPPORTED_VERSION, null); +- } else { +- status.updateState = UpdateState.NONE; ++ SharedPreferences preferences = OmahaBase.getSharedPreferences(); ++ status.latestVersion = preferences.getString(OmahaBase.PREF_LATEST_MODIFIED_VERSION, ""); ++ ++ status.updateState = UpdateState.NONE; ++ if (OmahaBase.isNewVersionAvailableByVersion(status.latestVersion)) { ++ status.updateState = UpdateState.INLINE_UPDATE_AVAILABLE; + } + + return status; +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/VersionNumberGetter.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/VersionNumberGetter.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/VersionNumberGetter.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/VersionNumberGetter.java +@@ -43,7 +43,8 @@ public class VersionNumberGetter { + private static VersionNumberGetter sInstanceForTests; + + /** If false, OmahaClient will never report that a newer version is available. */ +- private static boolean sEnableUpdateDetection = true; ++ // it must be false to not enable version control with Omaha server ++ private static boolean sEnableUpdateDetection = false; + + protected VersionNumberGetter() { } + +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/BromiteInlineUpdateController.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/BromiteInlineUpdateController.java +new file mode 100644 +--- /dev/null ++++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/BromiteInlineUpdateController.java +@@ -0,0 +1,204 @@ ++// Copyright 2021 The Ungoogled Chromium Authors. All rights reserved. ++// ++// This file is part of Ungoogled Chromium Android. ++// ++// Ungoogled Chromium Android is free software: you can redistribute it ++// and/or modify it under the terms of the GNU General Public License as ++// published by the Free Software Foundation, either version 3 of the ++// License, or any later version. ++// ++// Ungoogled Chromium Android is distributed in the hope that it will be ++// useful, but WITHOUT ANY WARRANTY; without even the implied warranty ++// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++// GNU General Public License for more details. ++// ++// You should have received a copy of the GNU General Public License ++// along with Ungoogled Chromium Android. If not, ++// see . ++ ++package org.chromium.chrome.browser.omaha.inline; ++ ++import static org.chromium.chrome.browser.omaha.UpdateConfigs.getUpdateNotificationInterval; ++ ++import android.app.Activity; ++import android.content.SharedPreferences; ++import android.os.Build; ++import android.text.format.DateUtils; ++import org.chromium.build.BuildConfig; ++ ++import androidx.annotation.Nullable; ++ ++import org.chromium.base.Callback; ++import org.chromium.base.Log; ++import org.chromium.base.task.AsyncTask; ++import org.chromium.base.task.PostTask; ++import org.chromium.chrome.browser.app.ChromeActivity; ++import org.chromium.chrome.browser.omaha.OmahaBase; ++import org.chromium.chrome.browser.omaha.UpdateConfigs; ++import org.chromium.chrome.browser.omaha.UpdateStatusProvider; ++import org.chromium.chrome.browser.profiles.Profile; ++import org.chromium.chrome.browser.tab.TabLaunchType; ++import org.chromium.chrome.browser.tabmodel.TabCreator; ++import org.chromium.chrome.browser.version.ChromeVersionInfo; ++import org.chromium.content_public.browser.LoadUrlParams; ++import org.chromium.content_public.browser.UiThreadTaskTraits; ++import org.chromium.ui.base.PageTransition; ++ ++import java.io.BufferedReader; ++import java.io.IOException; ++import java.io.InputStreamReader; ++import java.io.InputStream; ++import java.net.MalformedURLException; ++import java.net.URL; ++import java.net.HttpURLConnection; ++import java.util.regex.Pattern; ++ ++import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcher; ++import org.chromium.chrome.browser.endpoint_fetcher.EndpointResponse; ++import org.chromium.chrome.browser.omaha.VersionNumber; ++ ++class BromiteInlineUpdateController implements InlineUpdateController { ++ ++ private static final String TAG = "BromiteInlineUpdateController"; ++ private final String UPDATE_VERSION_URL = "https://github.com/bromite/bromite/releases/latest/download/"; ++ ++ private String getDownloadUrl() { ++ return UPDATE_VERSION_URL + BuildConfig.BUILD_TARGET_CPU + "_ChromePublic.apk"; ++ } ++ ++ private boolean mEnabled = true; ++ private Runnable mCallback; ++ private @Nullable @UpdateStatusProvider.UpdateState Integer mUpdateState = ++ UpdateStatusProvider.UpdateState.NONE; ++ ++ BromiteInlineUpdateController(Runnable callback) { ++ mCallback = callback; ++ } ++ ++ @Override ++ public void setEnabled(boolean enabled) { ++ if (mEnabled == enabled) return; ++ ++ mEnabled = enabled; ++ if (mEnabled) pullCurrentState(); ++ } ++ ++ @Override ++ public @Nullable @UpdateStatusProvider.UpdateState Integer getStatus() { ++ if (mEnabled) pullCurrentState(); ++ return mUpdateState; ++ } ++ ++ @Override ++ public void startUpdate(Activity activity) { ++ assert ChromeActivity.class.isInstance(activity); ++ ChromeActivity thisActivity = (ChromeActivity) activity; ++ String downloadUrl = getDownloadUrl(); ++ // Always open in new incognito tab ++ TabCreator tabCreator = thisActivity.getTabCreator(true); ++ tabCreator.createNewTab(new LoadUrlParams(downloadUrl, PageTransition.AUTO_BOOKMARK), ++ TabLaunchType.FROM_LINK, thisActivity.getActivityTab()); ++ } ++ ++ @Override ++ public void completeUpdate() { ++ } ++ ++ private void pullCurrentState() { ++ if (OmahaBase.getSharedPreferences() ++ .getBoolean(OmahaBase.PREF_ALLOW_INLINE_UPDATE, false) == false) { ++ Log.i(TAG, "Checking for update disabled by user"); ++ return; ++ } ++ ++ if (mUpdateState != UpdateStatusProvider.UpdateState.NONE) ++ return; ++ ++ if (shallUpdate() == false) ++ return; ++ ++ switch (mUpdateState) { ++ case UpdateStatusProvider.UpdateState.INLINE_UPDATE_AVAILABLE: ++ break; ++ case UpdateStatusProvider.UpdateState.NONE: ++ checkLatestVersion((ok) -> { ++ if (ok == false) return; ++ ++ SharedPreferences preferences = OmahaBase.getSharedPreferences(); ++ String latestVersion = preferences.getString(OmahaBase.PREF_LATEST_MODIFIED_VERSION, ""); ++ ++ if (OmahaBase.isNewVersionAvailableByVersion(latestVersion)) { ++ postStatus(UpdateStatusProvider.UpdateState.INLINE_UPDATE_AVAILABLE); ++ } else { ++ if (mUpdateState != UpdateStatusProvider.UpdateState.NONE) { ++ postStatus(UpdateStatusProvider.UpdateState.NONE); ++ } ++ } ++ }); ++ break; ++ case UpdateStatusProvider.UpdateState.INLINE_UPDATE_READY: ++ // Intentional fall through. ++ case UpdateStatusProvider.UpdateState.INLINE_UPDATE_FAILED: ++ // Intentional fall through. ++ case UpdateStatusProvider.UpdateState.INLINE_UPDATE_DOWNLOADING: ++ // Intentional fall through. ++ case UpdateStatusProvider.UpdateState.UNSUPPORTED_OS_VERSION: ++ // Intentional fall through. ++ default: ++ return; ++ } ++ } ++ ++ private boolean shallUpdate() { ++ long currentTime = System.currentTimeMillis(); ++ SharedPreferences preferences = OmahaBase.getSharedPreferences(); ++ long lastPushedTimeStamp = preferences.getLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, 0); ++ return currentTime - lastPushedTimeStamp >= getUpdateNotificationInterval(); ++ } ++ ++ private void checkLatestVersion(final Callback callback) { ++ assert UPDATE_VERSION_URL != null; ++ ++ OmahaBase.resetUpdatePrefs(); ++ ++ String urlToCheck = getDownloadUrl(); ++ Log.i(TAG, "Fetching with HEAD: " + urlToCheck); ++ ++ EndpointFetcher.nativeHeadWithNoAuth( ++ (endpointResponse) -> { ++ Log.i(TAG, "Obtained response"); ++ Log.i(TAG, "with message: '%s'", endpointResponse.getResponseString()); ++ Log.i(TAG, "and redirect: '%s'", endpointResponse.getRedirectUrl()); ++ ++ OmahaBase.updateLastPushedTimeStamp(System.currentTimeMillis()); ++ ++ if (endpointResponse.getRedirectUrl() != null) { ++ String[] parts = endpointResponse.getRedirectUrl() ++ .split(Pattern.quote("/")); ++ for(String part:parts) { ++ VersionNumber version = VersionNumber.fromString(part); ++ if (version != null) { ++ OmahaBase.setLastModifiedVersion(part); ++ callback.onResult(true); ++ return; ++ } ++ } ++ } else { ++ // retry after 1 hour ++ OmahaBase.updateLastPushedTimeStamp( ++ System.currentTimeMillis() - getUpdateNotificationInterval() - ++ DateUtils.HOUR_IN_MILLIS * 1); ++ Log.i(TAG, "Some error has occurred. I'll try again in 1 hour"); ++ } ++ ++ callback.onResult(false); ++ }, ++ Profile.getLastUsedRegularProfile(), ++ urlToCheck, /*timeout*/5000, /*follow_redirect*/false); ++ } ++ ++ private void postStatus(@UpdateStatusProvider.UpdateState int status) { ++ mUpdateState = status; ++ PostTask.postTask(UiThreadTaskTraits.DEFAULT, mCallback); ++ } ++} +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/InlineUpdateControllerFactory.java +@@ -19,8 +19,10 @@ public class InlineUpdateControllerFactory { + @FakeAppUpdateManagerWrapper.Type + int mockInlineEndState = UpdateConfigs.getMockInlineScenarioEndState(); + +- // No test scenario was in place, and the inline flow has not been enabled, so use a +- // controller with no functionality. +- return new NoopInlineUpdateController(callback); ++ if (ChromeFeatureList.isEnabled(ChromeFeatureList.INLINE_UPDATE_FLOW)) { ++ return new BromiteInlineUpdateController(callback); ++ } else { ++ return new NoopInlineUpdateController(callback); ++ } + } + } +diff --git a/chrome/browser/endpoint_fetcher/BUILD.gn b/chrome/browser/endpoint_fetcher/BUILD.gn +--- a/chrome/browser/endpoint_fetcher/BUILD.gn ++++ b/chrome/browser/endpoint_fetcher/BUILD.gn +@@ -14,6 +14,7 @@ android_library("java") { + sources = [ + "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java", + "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointResponse.java", ++ "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointHeaderResponse.java", + ] + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] + } +@@ -22,5 +23,6 @@ generate_jni("jni_headers") { + sources = [ + "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java", + "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointResponse.java", ++ "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointHeaderResponse.java", + ] + } +diff --git a/chrome/browser/endpoint_fetcher/endpoint_fetcher.cc b/chrome/browser/endpoint_fetcher/endpoint_fetcher.cc +--- a/chrome/browser/endpoint_fetcher/endpoint_fetcher.cc ++++ b/chrome/browser/endpoint_fetcher/endpoint_fetcher.cc +@@ -26,10 +26,15 @@ + #include "base/android/jni_string.h" + #include "chrome/browser/endpoint_fetcher/jni_headers/EndpointFetcher_jni.h" + #include "chrome/browser/endpoint_fetcher/jni_headers/EndpointResponse_jni.h" ++#include "chrome/browser/endpoint_fetcher/jni_headers/EndpointHeaderResponse_jni.h" + #include "chrome/browser/profiles/profile_android.h" + + #endif // defined(OS_ANDROID) + ++#include "net/base/load_flags.h" ++#include "net/http/http_status_code.h" ++#include "services/network/public/cpp/resource_request.h" ++ + namespace { + const char kContentTypeKey[] = "Content-Type"; + const char kDeveloperKey[] = "X-Developer-Key"; +@@ -150,6 +155,19 @@ EndpointFetcher::EndpointFetcher( + identity_manager_(nullptr), + sanitize_response_(true) {} + ++EndpointFetcher::EndpointFetcher( ++ Profile* const profile, ++ const GURL& url, ++ int64_t timeout_ms, ++ const net::NetworkTrafficAnnotationTag& annotation_tag) ++ : url_(url), ++ timeout_ms_(timeout_ms), ++ annotation_tag_(annotation_tag), ++ url_loader_factory_(profile->GetDefaultStoragePartition() ++ ->GetURLLoaderFactoryForBrowserProcess()), ++ identity_manager_(nullptr), ++ sanitize_response_(false) {} ++ + EndpointFetcher::~EndpointFetcher() = default; + + void EndpointFetcher::Fetch(EndpointFetcherCallback endpoint_fetcher_callback) { +@@ -279,6 +297,73 @@ void EndpointFetcher::OnSanitizationResult( + std::move(endpoint_fetcher_callback).Run(std::move(response)); + } + ++void EndpointFetcher::PerformHeadRequest( ++ EndpointFetcherCallback endpoint_fetcher_callback, ++ const char* key, ++ bool allow_redirect) { ++ ++ endpoint_fetcher_callback_ = std::move(endpoint_fetcher_callback); ++ ++ auto resource_request = std::make_unique(); ++ resource_request->method = "HEAD"; ++ resource_request->url = url_; ++ resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; ++ resource_request->load_flags = net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE ++ | net::LOAD_DO_NOT_SAVE_COOKIES; ++ if (allow_redirect == false) { ++ resource_request->redirect_mode = network::mojom::RedirectMode::kManual; ++ } ++ ++ simple_url_loader_ = network::SimpleURLLoader::Create( ++ std::move(resource_request), annotation_tag_); ++ simple_url_loader_->SetTimeoutDuration( ++ base::TimeDelta::FromMilliseconds(timeout_ms_)); ++ simple_url_loader_->SetAllowHttpErrorResults(true); ++ ++ if(!response_) ++ response_ = std::make_unique(); ++ ++ if (allow_redirect == false) { ++ simple_url_loader_->SetOnRedirectCallback(base::BindRepeating( ++ &EndpointFetcher::OnSimpleLoaderRedirect, base::Unretained(this))); ++ } ++ ++ simple_url_loader_->DownloadHeadersOnly( ++ url_loader_factory_.get(), ++ base::BindOnce(&EndpointFetcher::OnURLLoadComplete, ++ base::Unretained(this))); ++} ++ ++void EndpointFetcher::OnSimpleLoaderRedirect( ++ const net::RedirectInfo& redirect_info, ++ const network::mojom::URLResponseHead& response_head, ++ std::vector* removed_headers) { ++ url_ = redirect_info.new_url; ++ if (response_->redirect_url.empty()) ++ response_->redirect_url = url_.spec(); ++ ++ PerformHeadRequest(std::move(endpoint_fetcher_callback_), nullptr, true); ++} ++ ++void EndpointFetcher::OnURLLoadComplete( ++ scoped_refptr headers) { ++ if (!endpoint_fetcher_callback_) ++ return; ++ ++ if (headers) { ++ if (response_->redirect_url.empty()) { ++ std::string location; ++ if (simple_url_loader_->ResponseInfo()->headers->IsRedirect(&location)) { ++ response_->redirect_url = location; ++ } ++ } ++ } ++ ++ std::string net_error = net::ErrorToString(simple_url_loader_->NetError()); ++ response_->response = net_error; ++ std::move(endpoint_fetcher_callback_).Run(std::move(response_)); ++} ++ + #if defined(OS_ANDROID) + namespace { + static void OnEndpointFetcherComplete( +@@ -295,6 +380,25 @@ static void OnEndpointFetcherComplete( + base::android::AttachCurrentThread(), + std::move(endpoint_response->response)))); + } ++ ++static void OnEndpointFetcherHeadComplete( ++ const base::android::JavaRef& jcaller, ++ // Passing the endpoint_fetcher ensures the endpoint_fetcher's ++ // lifetime extends to the callback and is not destroyed ++ // prematurely (which would result in cancellation of the request). ++ std::unique_ptr endpoint_fetcher, ++ std::unique_ptr endpoint_response) { ++ base::android::RunObjectCallbackAndroid( ++ jcaller, Java_EndpointHeaderResponse_createEndpointResponse( ++ base::android::AttachCurrentThread(), ++ base::android::ConvertUTF8ToJavaString( ++ base::android::AttachCurrentThread(), ++ std::move(endpoint_response->response)), ++ base::android::ConvertUTF8ToJavaString( ++ base::android::AttachCurrentThread(), ++ std::move(endpoint_response->redirect_url)))); ++} ++ + } // namespace + + // TODO(crbug.com/1077537) Create a KeyProvider so +@@ -380,4 +484,25 @@ static void JNI_EndpointFetcher_NativeFetchWithNoAuth( + nullptr); + } + ++static void JNI_EndpointFetcher_NativeHeadWithNoAuth( ++ JNIEnv* env, ++ const base::android::JavaParamRef& jprofile, ++ const base::android::JavaParamRef& jurl, ++ jlong jtimeout, jboolean allow_redirect, ++ const base::android::JavaParamRef& jcallback) { ++ auto endpoint_fetcher = std::make_unique( ++ ProfileAndroid::FromProfileAndroid(jprofile), ++ GURL(base::android::ConvertJavaStringToUTF8(env, jurl)), ++ jtimeout, ++ NO_TRAFFIC_ANNOTATION_YET); ++ auto* const endpoint_fetcher_ptr = endpoint_fetcher.get(); ++ endpoint_fetcher_ptr->PerformHeadRequest( ++ base::BindOnce(&OnEndpointFetcherHeadComplete, ++ base::android::ScopedJavaGlobalRef(jcallback), ++ // unique_ptr endpoint_fetcher is passed until the callback ++ // to ensure its lifetime across the request. ++ std::move(endpoint_fetcher)), ++ nullptr, allow_redirect); ++} ++ + #endif // defined(OS_ANDROID) +diff --git a/chrome/browser/endpoint_fetcher/endpoint_fetcher.h b/chrome/browser/endpoint_fetcher/endpoint_fetcher.h +--- a/chrome/browser/endpoint_fetcher/endpoint_fetcher.h ++++ b/chrome/browser/endpoint_fetcher/endpoint_fetcher.h +@@ -14,6 +14,8 @@ + #include "components/signin/public/identity_manager/scope_set.h" + #include "net/traffic_annotation/network_traffic_annotation.h" + #include "services/data_decoder/public/cpp/json_sanitizer.h" ++#include "services/network/public/cpp/resource_request.h" ++#include "services/network/public/mojom/url_response_head.mojom.h" + + namespace network { + struct ResourceRequest; +@@ -31,6 +33,8 @@ class Profile; + + struct EndpointResponse { + std::string response; ++ long last_modified; ++ std::string redirect_url; + // TODO(crbug.com/993393) Add more detailed error messaging + }; + +@@ -77,6 +81,12 @@ class EndpointFetcher { + const GURL& url, + const net::NetworkTrafficAnnotationTag& annotation_tag); + ++ // Constructor if no authentication is needed, with timeout ++ EndpointFetcher(Profile* const profile, ++ const GURL& url, ++ int64_t timeout_ms, ++ const net::NetworkTrafficAnnotationTag& annotation_tag); ++ + // Used for tests. Can be used if caller constructs their own + // url_loader_factory and identity_manager. + EndpointFetcher( +@@ -113,6 +123,10 @@ class EndpointFetcher { + virtual void PerformRequest(EndpointFetcherCallback endpoint_fetcher_callback, + const char* key); + ++ virtual void PerformHeadRequest(EndpointFetcherCallback endpoint_fetcher_callback, ++ const char* key, ++ bool allow_redirect); ++ + protected: + // Used for Mock only. see MockEndpointFetcher class. + explicit EndpointFetcher( +@@ -126,6 +140,10 @@ class EndpointFetcher { + std::unique_ptr response_body); + void OnSanitizationResult(EndpointFetcherCallback endpoint_fetcher_callback, + data_decoder::JsonSanitizer::Result result); ++ void OnURLLoadComplete(scoped_refptr headers); ++ void OnSimpleLoaderRedirect(const net::RedirectInfo& redirect_info, ++ const network::mojom::URLResponseHead& response_head, ++ std::vector* removed_headers); + + enum AuthType { CHROME_API_KEY, OAUTH, NO_AUTH }; + AuthType auth_type_; +@@ -133,7 +151,7 @@ class EndpointFetcher { + // Members set in constructor to be passed to network::ResourceRequest or + // network::SimpleURLLoader. + const std::string oauth_consumer_name_; +- const GURL url_; ++ GURL url_; + const std::string http_method_; + const std::string content_type_; + int64_t timeout_ms_; +@@ -152,6 +170,9 @@ class EndpointFetcher { + access_token_fetcher_; + std::unique_ptr simple_url_loader_; + ++ EndpointFetcherCallback endpoint_fetcher_callback_; ++ std::unique_ptr response_; ++ + base::WeakPtrFactory weak_ptr_factory_{this}; + }; + +diff --git a/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java b/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java +--- a/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java ++++ b/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java +@@ -68,6 +68,14 @@ public final class EndpointFetcher { + profile, url, httpsMethod, contentType, postData, timeout, headers, callback); + } + ++ @MainThread ++ public static void nativeHeadWithNoAuth( ++ Callback callback, Profile profile, ++ String url, long timeout, boolean allow_redirect) { ++ EndpointFetcherJni.get().nativeHeadWithNoAuth( ++ profile, url, timeout, allow_redirect, callback); ++ } ++ + @NativeMethods + public interface Natives { + void nativeFetchOAuth(Profile profile, String oathConsumerName, String url, +@@ -78,5 +86,8 @@ public final class EndpointFetcher { + Callback callback); + void nativeFetchWithNoAuth( + Profile profile, String url, Callback callback); ++ void nativeHeadWithNoAuth( ++ Profile profile, String url, long timeout, boolean allow_redirect, ++ Callback callback); + } + } +diff --git a/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointHeaderResponse.java b/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointHeaderResponse.java +new file mode 100644 +--- /dev/null ++++ b/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointHeaderResponse.java +@@ -0,0 +1,31 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++package org.chromium.chrome.browser.endpoint_fetcher; ++ ++import org.chromium.base.annotations.CalledByNative; ++ ++public class EndpointHeaderResponse { ++ private final String mResponseString; ++ private final String mRedirectUrl; ++ ++ public EndpointHeaderResponse(String responseString, String redirectUrl) { ++ mResponseString = responseString; ++ mRedirectUrl = redirectUrl; ++ } ++ ++ public String getResponseString() { ++ return mResponseString; ++ } ++ ++ public String getRedirectUrl() { ++ return mRedirectUrl; ++ } ++ ++ @CalledByNative ++ private static EndpointHeaderResponse createEndpointResponse( ++ String response, String redirectUrl) { ++ return new EndpointHeaderResponse(response, redirectUrl); ++ } ++} +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 +@@ -2059,7 +2059,7 @@ + { + "name": "enable-inline-update-flow", + "owners": [ "nyquist", "dtrainor" ], +- "expiry_milestone": 83 ++ "expiry_milestone": -1 + }, + { + "name": "enable-input-event-logging", +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 +@@ -3705,10 +3705,9 @@ const char kVoiceButtonInTopToolbarDescription[] = + "Enables showing the voice search button in the top toolbar. Enabling " + "Adaptive Button overrides this."; + +-const char kInlineUpdateFlowName[] = "Enable Google Play inline update flow"; ++const char kInlineUpdateFlowName[] = "Enable inline update flow"; + const char kInlineUpdateFlowDescription[] = +- "When this flag is set, instead of taking the user to the Google Play " +- "Store when an update is available, the user is presented with an inline " ++ "When this flag is set, the user is presented with an inline " + "flow where they do not have to leave Chrome until the update is ready " + "to install."; + +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 +@@ -594,7 +594,7 @@ const base::Feature kIncognitoScreenshot{"IncognitoScreenshot", + base::FEATURE_DISABLED_BY_DEFAULT}; + + const base::Feature kInlineUpdateFlow{"InlineUpdateFlow", +- base::FEATURE_DISABLED_BY_DEFAULT}; ++ base::FEATURE_ENABLED_BY_DEFAULT}; + + const base::Feature kInstantStart{"InstantStart", + base::FEATURE_DISABLED_BY_DEFAULT}; +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 +@@ -1631,6 +1631,12 @@ Your Google account may have other forms of browsing history like searches and a + + Chrome updates are no longer supported for this version of Android + ++ ++ Allow checking for updates ++ ++ ++ Check for updates by contacting the Bromite repo ++ + + + +@@ -3059,7 +3065,7 @@ To change this setting, <resetlink>reset sync

+ +- Update Chrome ++ Update Bromite + + + Newer version is available +-- +2.17.1 +