From: uazo Date: Sun, 3 Oct 2021 16:18:24 +0000 Subject: Enable share intent This patch allows to activate the management of android.intent.action.SEND with new flag "shared-intent-ui" default active. See also: https://github.com/bromite/bromite/issues/1062 Original License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html --- chrome/android/chrome_java_resources.gni | 1 + chrome/android/chrome_java_sources.gni | 1 + chrome/android/java/AndroidManifest.xml | 24 +++- .../res/layout/sharing_intent_content.xml | 87 +++++++++++++ .../chrome/browser/IntentHandler.java | 16 ++- .../browser/LaunchIntentDispatcher.java | 2 +- .../init/ProcessInitializationHandler.java | 3 + .../SharedIntentShareActivity.java | 119 ++++++++++++++++++ chrome/browser/about_flags.cc | 4 + chrome/browser/flag_descriptions.cc | 5 + chrome/browser/flag_descriptions.h | 3 + .../flags/android/chrome_feature_list.cc | 5 + .../flags/android/chrome_feature_list.h | 1 + .../browser/flags/ChromeFeatureList.java | 1 + .../strings/android_chrome_strings.grd | 13 ++ 15 files changed, 277 insertions(+), 8 deletions(-) create mode 100644 chrome/android/java/res/layout/sharing_intent_content.xml create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_intent/SharedIntentShareActivity.java diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni --- a/chrome/android/chrome_java_resources.gni +++ b/chrome/android/chrome_java_resources.gni @@ -598,6 +598,7 @@ chrome_java_resources = [ "java/res/layout/signin_activity.xml", "java/res/layout/status_indicator_container.xml", "java/res/layout/suggestions_tile_view_condensed.xml", + "java/res/layout/sharing_intent_content.xml", "java/res/layout/suspended_tab.xml", "java/res/layout/sync_custom_passphrase.xml", "java/res/layout/sync_enter_passphrase.xml", 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 @@ -1037,6 +1037,7 @@ chrome_java_sources = [ "java/src/org/chromium/chrome/browser/signin/SyncConsentActivity.java", "java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java", "java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java", + "java/src/org/chromium/chrome/browser/sharing/shared_intent/SharedIntentShareActivity.java", "java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java", "java/src/org/chromium/chrome/browser/site_settings/CookieControlsServiceBridge.java", "java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java", 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 @@ -242,12 +242,6 @@ by a child template that "extends" this file. - - - - - - @@ -362,6 +356,24 @@ by a child template that "extends" this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java --- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java @@ -196,6 +196,9 @@ public class IntentHandler { private static final String EXTRA_TAB_LAUNCH_TYPE = "org.chromium.chrome.browser.tab_launch_type"; + private static final String EXTRA_TAB_FORCE_INCOGNITO_TYPE = + "org.chromium.chrome.browser.force_incognito"; + /** * A hash code for the URL to verify intent data hasn't been modified. */ @@ -1264,6 +1267,17 @@ public class IntentHandler { return IntentUtils.safeGetSerializableExtra(intent, EXTRA_TAB_LAUNCH_TYPE); } + public static void setForceIncognitoMode(Intent intent) { + intent.putExtra(EXTRA_TAB_FORCE_INCOGNITO_TYPE, 1); + intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, true); + setTabLaunchType(intent, TabLaunchType.FROM_EXTERNAL_APP); + } + + public static boolean isForceIncognitoMode(Intent intent) { + Integer value = IntentUtils.safeGetSerializableExtra(intent, EXTRA_TAB_FORCE_INCOGNITO_TYPE); + return value == null ? false : value == 1; + } + /** * Creates an Intent that will launch a ChromeTabbedActivity on the new tab page. The Intent * will be trusted and therefore able to launch Incognito tabs. @@ -1395,7 +1409,7 @@ public class IntentHandler { String headers = getExtraHeadersFromIntent(intent); headers = maybeAddAdditionalContentHeaders(intent, url, headers); - if (IntentHandler.wasIntentSenderChrome(intent)) { + if (IntentHandler.wasIntentSenderChrome(intent) && !isForceIncognitoMode(intent)) { // Handle post data case. String postDataType = IntentUtils.safeGetStringExtra(intent, IntentHandler.EXTRA_POST_DATA_TYPE); diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java --- a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java @@ -429,8 +429,8 @@ public class LaunchIntentDispatcher { /*incognito*/true); newIntent.setData(mIntent.getData()); newIntent.setPackage(applicationContext.getPackageName()); - IntentHandler.setTabLaunchType(newIntent, TabLaunchType.FROM_EXTERNAL_APP); newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + IntentHandler.setForceIncognitoMode(newIntent); } if (!chromeTabbedTaskExists()) { newIntent.putExtra(IntentHandler.EXTRA_STARTED_TABBED_CHROME_TASK, true); diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java @@ -86,6 +86,7 @@ import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData; import org.chromium.chrome.browser.ui.cars.DrivingRestrictionsManager; import org.chromium.chrome.browser.ui.hats.SurveyClientFactory; import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityPreferencesManager; +import org.chromium.chrome.browser.sharing.shared_intent.SharedIntentShareActivity; import org.chromium.chrome.browser.usb.UsbNotificationManager; import org.chromium.chrome.browser.util.AfterStartupTaskUtils; import org.chromium.chrome.browser.webapps.WebappRegistry; @@ -439,6 +440,8 @@ public class ProcessInitializationHandler { .resolveClearDataDialogResultRecorder()::makeDeferredRecordings); deferredStartupHandler.addDeferredTask(WebApkUninstallUmaTracker::recordDeferredUma); + deferredStartupHandler.addDeferredTask( + () -> SharedIntentShareActivity.updateComponentEnabledState()); deferredStartupHandler.addDeferredTask( () -> IncognitoTabLauncher.updateComponentEnabledState()); deferredStartupHandler.addDeferredTask( diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_intent/SharedIntentShareActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_intent/SharedIntentShareActivity.java new file mode 100644 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_intent/SharedIntentShareActivity.java @@ -0,0 +1,119 @@ +// 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.sharing.shared_intent; + +import org.chromium.base.Log; + +import android.content.res.Resources; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.view.View; +import android.widget.TextView; +import android.net.Uri; + +import org.chromium.base.ContextUtils; +import org.chromium.base.IntentUtils; +import org.chromium.base.ThreadUtils; +import org.chromium.base.task.PostTask; +import org.chromium.base.task.TaskTraits; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.AlwaysIncognitoLinkInterceptor; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.init.AsyncInitializationActivity; +import org.chromium.chrome.browser.LaunchIntentDispatcher; +import org.chromium.chrome.browser.IntentHandler; +import org.chromium.ui.widget.ButtonCompat; + +/** + * Activity to display device targets to share text. + */ +public class SharedIntentShareActivity + extends AsyncInitializationActivity { + + /** + * Checks whether sending shared clipboard message is enabled for the user and enables/disables + * the SharedIntentShareActivity appropriately. This call requires native to be loaded. + */ + public static void updateComponentEnabledState() { + boolean enabled = ChromeFeatureList.isEnabled(ChromeFeatureList.SHARED_INTENT_UI); + PostTask.postTask(TaskTraits.USER_VISIBLE, () -> setComponentEnabled(enabled)); + } + + /** + * Sets whether or not the SharedIntentShareActivity should be enabled. This may trigger a + * StrictMode violation so shouldn't be called on the UI thread. + */ + private static void setComponentEnabled(boolean enabled) { + ThreadUtils.assertOnBackgroundThread(); + Context context = ContextUtils.getApplicationContext(); + PackageManager packageManager = context.getPackageManager(); + ComponentName componentName = + new ComponentName(context, SharedIntentShareActivity.class); + + int newState = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + + // This indicates that we don't want to kill Chrome when changing component enabled state. + int flags = PackageManager.DONT_KILL_APP; + + if (packageManager.getComponentEnabledSetting(componentName) != newState) { + packageManager.setComponentEnabledSetting(componentName, newState, flags); + } + } + + @Override + protected void triggerLayoutInflation() { + setContentView(R.layout.sharing_intent_content); + + String linkUrl = IntentUtils.safeGetStringExtra(getIntent(), Intent.EXTRA_TEXT); + Resources resources = ContextUtils.getApplicationContext().getResources(); + TextView share_message_text = findViewById(R.id.share_message_text); + share_message_text.setText( + resources.getString(R.string.shared_intent_share_activity_text, linkUrl)); + + View mask = findViewById(R.id.mask); + mask.setOnClickListener(v -> finish()); + + ButtonCompat open_url_button = findViewById(R.id.open_url_button); + open_url_button.setVisibility(View.VISIBLE); + open_url_button.setOnClickListener(view -> { + Context applicationContext = ContextUtils.getApplicationContext(); + Intent chromeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(linkUrl)); + chromeIntent.setPackage(applicationContext.getPackageName()); + chromeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + LaunchIntentDispatcher.dispatch(this, chromeIntent); + finish(); + }); + + ButtonCompat open_url_incognito_button = findViewById(R.id.open_url_incognito_button); + open_url_incognito_button.setVisibility(View.VISIBLE); + open_url_incognito_button.setOnClickListener(view -> { + Context applicationContext = ContextUtils.getApplicationContext(); + Intent chromeIntent = IntentHandler.createTrustedOpenNewTabIntent(applicationContext, + /*incognito*/true); + + chromeIntent.setData(Uri.parse(linkUrl)); + chromeIntent.setPackage(applicationContext.getPackageName()); + chromeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + IntentHandler.setForceIncognitoMode(chromeIntent); + + LaunchIntentDispatcher.dispatch(this, chromeIntent); + finish(); + }); + + if (AlwaysIncognitoLinkInterceptor.isAlwaysIncognito()) + open_url_incognito_button.setVisibility(View.GONE); + + onInitialLayoutInflationComplete(); + } + + @Override + public boolean shouldStartGpuProcess() { + return false; + } +} 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 @@ -10234,6 +10234,10 @@ const FeatureEntry kFeatureEntries[] = { features::kBrokerFileOperationsOnDiskCacheInNetworkService)}, #if BUILDFLAG(IS_ANDROID) + {"shared-intent-ui", flag_descriptions::kSharedIntentUIName, + flag_descriptions::kSharedIntentUIDescription, kOsAll, + FEATURE_VALUE_TYPE(chrome::android::kSharedIntentUI)}, + {"enable-commerce-hint-android", flag_descriptions::kCommerceHintAndroidName, flag_descriptions::kCommerceHintAndroidDescription, kOsAndroid, 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 @@ -3220,6 +3220,11 @@ const char kIsolateOriginsDescription[] = "Requires dedicated processes for an additional set of origins, " "specified as a comma-separated list."; +const char kSharedIntentUIName[] = + "Enable shared feature"; +const char kSharedIntentUIDescription[] = + "Enables shared feature"; + const char kIsolationByDefaultName[] = "Change web-facing behaviors that prevent origin-level isolation"; const char kIsolationByDefaultDescription[] = 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 @@ -1866,6 +1866,9 @@ extern const char kIsolateOriginsDescription[]; extern const char kIsolationByDefaultName[]; extern const char kIsolationByDefaultDescription[]; +extern const char kSharedIntentUIName[]; +extern const char kSharedIntentUIDescription[]; + extern const char kSiteIsolationOptOutName[]; extern const char kSiteIsolationOptOutDescription[]; 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 @@ -294,6 +294,7 @@ const base::Feature* const kFeaturesExposedToJava[] = { &kReengagementNotification, &kSearchReadyOmniboxFeature, &kRelatedSearches, + &kSharedIntentUI, &kReportParentalControlSitesChild, &kRequestDesktopSiteDefaults, &kRequestDesktopSiteDefaultsControl, @@ -1035,6 +1036,10 @@ BASE_FEATURE(kScrollToTLDOptimization, "ScrollToTLDOptimization", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kSharedIntentUI, + "SharedIntentUI", + base::FEATURE_ENABLED_BY_DEFAULT); + BASE_FEATURE(kShowScrollableMVTOnNTPAndroid, "ShowScrollableMVTOnNTPAndroid", base::FEATURE_DISABLED_BY_DEFAULT); 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 @@ -176,6 +176,7 @@ BASE_DECLARE_FEATURE(kRequestDesktopSiteDefaultsLogging); BASE_DECLARE_FEATURE(kRestoreTabsOnFRE); BASE_DECLARE_FEATURE(kSearchEnginesPromoV3); BASE_DECLARE_FEATURE(kSearchReadyOmniboxFeature); +BASE_DECLARE_FEATURE(kSharedIntentUI); BASE_DECLARE_FEATURE(kSharingHubLinkToggle); BASE_DECLARE_FEATURE(kShowScrollableMVTOnNTPAndroid); BASE_DECLARE_FEATURE(kFeedPositionAndroid); 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 @@ -395,6 +395,7 @@ public abstract class ChromeFeatureList { public static final String REACHED_CODE_PROFILER = "ReachedCodeProfiler"; public static final String READALOUD = "ReadAloud"; public static final String READER_MODE_IN_CCT = "ReaderModeInCCT"; + public static final String SHARED_INTENT_UI = "SharedIntentUI"; public static final String RECORD_SUPPRESSION_METRICS = "RecordSuppressionMetrics"; public static final String RECOVER_FROM_NEVER_SAVE_ANDROID = "RecoverFromNeverSaveAndroid_LAUNCHED"; 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 @@ -5312,6 +5312,19 @@ To change this setting, <resetlink>reset sync

+ + Open URL with Bromite + + + Will open %1$s with Bromite + + + Open with Bromite + + + Open with Bromite Incognito + + Submit %1$s123 on %2$sZoe's Macbook? -- 2.25.1