Add default browser promo dialogs
Show default browser promo dialogs on launch to encourage users to set Chrome as their default browser. Bug: 1090103 Change-Id: I9ebbcdb30dbe68b84035a0e324205219b5ccf267 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2228191 Commit-Queue: Lijin Shen <lazzzis@google.com> Reviewed-by: Yaron Friedman <yfriedman@chromium.org> Reviewed-by: Theresa <twellington@chromium.org> Reviewed-by: Pavel Yatsuk <pavely@chromium.org> Cr-Commit-Position: refs/heads/master@{#777507}
This commit is contained in:
chrome
android
browser
about_flags.ccflag-metadata.jsonflag_descriptions.ccflag_descriptions.h
flags
android
preferences
android
java
src
org
chromium
chrome
browser
preferences
ui
android
default_browser_promo
strings
android_chrome_strings.grd
android_chrome_strings_grd
IDS_DEFAULT_BROWSER_PROMO_DIALOG_CHOOSE_CHROME_BUTTON.png.sha1IDS_DEFAULT_BROWSER_PROMO_DIALOG_DESC.png.sha1IDS_DEFAULT_BROWSER_PROMO_DIALOG_DISAMBIGUATION_SHEET_STEPS.png.sha1IDS_DEFAULT_BROWSER_PROMO_DIALOG_GO_TO_SETTINGS_BUTTON.png.sha1IDS_DEFAULT_BROWSER_PROMO_DIALOG_ROLE_MANAGER_STEPS.png.sha1IDS_DEFAULT_BROWSER_PROMO_DIALOG_SYSTEM_SETTINGS_STEPS.png.sha1IDS_DEFAULT_BROWSER_PROMO_DIALOG_TITLE.png.sha1
components/browser_ui/widget/android/java
tools/metrics/histograms
@ -184,6 +184,7 @@ android_resources("chrome_app_java_resources") {
|
||||
"//chrome/android/webapk/libs/common:splash_resources",
|
||||
"//chrome/app:java_strings_grd",
|
||||
"//chrome/browser/ui/android/appmenu:java_resources",
|
||||
"//chrome/browser/ui/android/default_browser_promo:java_resources",
|
||||
"//chrome/browser/ui/android/favicon:java_resources",
|
||||
"//chrome/browser/ui/android/strings:ui_strings_grd",
|
||||
"//chrome/browser/ui/messages/android:java_resources",
|
||||
@ -318,6 +319,7 @@ android_library("chrome_java") {
|
||||
"//chrome/browser/ui:infobar_android_enums_java",
|
||||
"//chrome/browser/ui/android/appmenu:factory_java",
|
||||
"//chrome/browser/ui/android/appmenu:java",
|
||||
"//chrome/browser/ui/android/default_browser_promo:java",
|
||||
"//chrome/browser/ui/android/favicon:java",
|
||||
"//chrome/browser/ui/android/native_page:java",
|
||||
"//chrome/browser/ui/messages/android:java",
|
||||
@ -744,6 +746,8 @@ junit_binary("chrome_junit_tests") {
|
||||
"//chrome/browser/thumbnail:java",
|
||||
"//chrome/browser/ui/android/appmenu:java",
|
||||
"//chrome/browser/ui/android/appmenu/internal:junit",
|
||||
"//chrome/browser/ui/android/default_browser_promo:java",
|
||||
"//chrome/browser/ui/android/default_browser_promo:junit",
|
||||
"//chrome/browser/ui/android/favicon:java",
|
||||
"//chrome/browser/ui/android/native_page:java",
|
||||
"//chrome/browser/ui/messages/android:java",
|
||||
@ -920,6 +924,8 @@ android_library("chrome_test_java") {
|
||||
"//chrome/browser/thumbnail:javatests",
|
||||
"//chrome/browser/ui/android/appmenu:java",
|
||||
"//chrome/browser/ui/android/appmenu/test:test_support_java",
|
||||
"//chrome/browser/ui/android/default_browser_promo:java",
|
||||
"//chrome/browser/ui/android/default_browser_promo:javatests",
|
||||
"//chrome/browser/ui/android/favicon:java",
|
||||
"//chrome/browser/ui/android/native_page:java",
|
||||
"//chrome/browser/ui/messages/android:java",
|
||||
|
@ -9,6 +9,7 @@ include_rules = [
|
||||
"+chrome/browser/thumbnail/generator/android/java",
|
||||
"+chrome/browser/ui/android/appmenu",
|
||||
"-chrome/browser/ui/android/appmenu/internal",
|
||||
"+chrome/browser/ui/android/default_browser_promo",
|
||||
"+chrome/browser/ui/messages/android/java",
|
||||
"+chrome/browser/download/android/java",
|
||||
"+chrome/browser/image_fetcher/android/java",
|
||||
|
@ -13,6 +13,7 @@ import org.chromium.base.metrics.RecordHistogram;
|
||||
import org.chromium.base.metrics.RecordUserAction;
|
||||
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
|
||||
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
|
||||
import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils;
|
||||
|
||||
/**
|
||||
* Records the behavior metrics after an ACTION_MAIN intent is received.
|
||||
@ -105,6 +106,8 @@ public class MainIntentBehaviorMetrics {
|
||||
RecordHistogram.recordEnumeratedHistogram("MobileStartup.LaunchType",
|
||||
isLaunchFromIcon ? LAUNCH_FROM_ICON : LAUNCH_NOT_FROM_ICON, LAUNCH_BOUNDARY);
|
||||
|
||||
DefaultBrowserPromoUtils.incrementSessionCount();
|
||||
|
||||
ThreadUtils.getUiThreadHandler().removeCallbacks(mLogLaunchRunnable);
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import org.chromium.chrome.browser.toolbar.ToolbarButtonInProductHelpController;
|
||||
import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarConfiguration;
|
||||
import org.chromium.chrome.browser.ui.RootUiCoordinator;
|
||||
import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
|
||||
import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils;
|
||||
import org.chromium.chrome.browser.ui.tablet.emptybackground.EmptyBackgroundViewWrapper;
|
||||
import org.chromium.chrome.browser.vr.VrModuleProvider;
|
||||
import org.chromium.content_public.browser.UiThreadTaskTraits;
|
||||
@ -348,6 +349,9 @@ public class TabbedRootUiCoordinator extends RootUiCoordinator implements Native
|
||||
mActivity, mActivity.getTabModelSelector().getCurrentModel().isIncognito())) {
|
||||
return true;
|
||||
}
|
||||
if (DefaultBrowserPromoUtils.prepareLaunchPromoIfNeeded(mActivity)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return LanguageAskPrompt.maybeShowLanguageAskPrompt(mActivity);
|
||||
}
|
||||
|
@ -5596,6 +5596,11 @@ const FeatureEntry kFeatureEntries[] = {
|
||||
#endif // !defined(OS_ANDROID)
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
{"android-default-browser-promo",
|
||||
flag_descriptions::kAndroidDefaultBrowserPromoName,
|
||||
flag_descriptions::kAndroidDefaultBrowserPromoDescription, kOsAndroid,
|
||||
FEATURE_VALUE_TYPE(chrome::android::kAndroidDefaultBrowserPromo)},
|
||||
|
||||
{"android-multiple-display", flag_descriptions::kAndroidMultipleDisplayName,
|
||||
flag_descriptions::kAndroidMultipleDisplayDescription, kOsAndroid,
|
||||
FEATURE_VALUE_TYPE(chrome::android::kAndroidMultipleDisplay)},
|
||||
|
@ -93,6 +93,11 @@
|
||||
"owners": [ "kdillon@chromium.org" ],
|
||||
"expiry_milestone": 88
|
||||
},
|
||||
{
|
||||
"name": "android-default-browser-promo",
|
||||
"owners": [ "lazzzis@google.com", "twellington" ],
|
||||
"expiry_milestone": 91
|
||||
},
|
||||
{
|
||||
"name": "android-files-in-files-app",
|
||||
"owners": [ "fukino" ],
|
||||
|
@ -2333,6 +2333,10 @@ const char kAndroidAutofillAccessibilityName[] = "Autofill Accessibility";
|
||||
const char kAndroidAutofillAccessibilityDescription[] =
|
||||
"Enable accessibility for autofill popup.";
|
||||
|
||||
const char kAndroidDefaultBrowserPromoName[] = "Default Browser Promo";
|
||||
const char kAndroidDefaultBrowserPromoDescription[] =
|
||||
"Shows a promo dialog to set Chrome as the default browser";
|
||||
|
||||
const char kAndroidMultipleDisplayName[] = "Multiple Display";
|
||||
const char kAndroidMultipleDisplayDescription[] =
|
||||
"When enabled, tabs can be moved to the secondary display.";
|
||||
|
@ -1358,6 +1358,9 @@ extern const char kEnableVulkanDescription[];
|
||||
extern const char kAndroidAutofillAccessibilityName[];
|
||||
extern const char kAndroidAutofillAccessibilityDescription[];
|
||||
|
||||
extern const char kAndroidDefaultBrowserPromoName[];
|
||||
extern const char kAndroidDefaultBrowserPromoDescription[];
|
||||
|
||||
extern const char kAndroidMultipleDisplayName[];
|
||||
extern const char kAndroidMultipleDisplayDescription[];
|
||||
|
||||
|
@ -102,6 +102,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
|
||||
&kAllowNewIncognitoTabIntents,
|
||||
&kAllowRemoteContextForNotifications,
|
||||
&kAndroidBlockIntentNonSafelistedHeaders,
|
||||
&kAndroidDefaultBrowserPromo,
|
||||
&kAndroidMultipleDisplay,
|
||||
&kAndroidNightModeTabReparenting,
|
||||
&kAndroidPartnerCustomizationPhenotype,
|
||||
@ -273,6 +274,9 @@ const base::Feature kAdjustWebApkInstallationSpace = {
|
||||
const base::Feature kAndroidBlockIntentNonSafelistedHeaders{
|
||||
"AndroidBlockIntentNonSafelistedHeaders", base::FEATURE_ENABLED_BY_DEFAULT};
|
||||
|
||||
const base::Feature kAndroidDefaultBrowserPromo{
|
||||
"AndroidDefaultBrowserPromo", base::FEATURE_DISABLED_BY_DEFAULT};
|
||||
|
||||
const base::Feature kAndroidMultipleDisplay{"AndroidMultipleDisplay",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT};
|
||||
|
||||
|
@ -16,6 +16,7 @@ extern const base::Feature kAdjustWebApkInstallationSpace;
|
||||
extern const base::Feature kAllowNewIncognitoTabIntents;
|
||||
extern const base::Feature kAllowRemoteContextForNotifications;
|
||||
extern const base::Feature kAndroidBlockIntentNonSafelistedHeaders;
|
||||
extern const base::Feature kAndroidDefaultBrowserPromo;
|
||||
extern const base::Feature kAndroidMultipleDisplay;
|
||||
extern const base::Feature kAndroidNightModeTabReparenting;
|
||||
extern const base::Feature kAndroidPartnerCustomizationPhenotype;
|
||||
|
@ -205,6 +205,7 @@ public abstract class ChromeFeatureList {
|
||||
public static final String ADJUST_WEBAPK_INSTALLATION_SPACE = "AdjustWebApkInstallationSpace";
|
||||
public static final String ANDROID_BLOCK_INTENT_NON_SAFELISTED_HEADERS =
|
||||
"AndroidBlockIntentNonSafelistedHeaders";
|
||||
public static final String ANDROID_DEFAULT_BROWSER_PROMO = "AndroidDefaultBrowserPromo";
|
||||
public static final String ANDROID_MULTIPLE_DISPLAY = "AndroidMultipleDisplay";
|
||||
public static final String ANDROID_NIGHT_MODE_TAB_REPARENTING =
|
||||
"AndroidNightModeTabReparenting";
|
||||
|
@ -279,6 +279,14 @@ public final class ChromePreferenceKeys {
|
||||
public static final String DATA_REDUCTION_SITE_BREAKDOWN_ALLOWED_DATE =
|
||||
"data_reduction_site_breakdown_allowed_date";
|
||||
|
||||
/**
|
||||
* Keys used to save whether it is ready to promo.
|
||||
*/
|
||||
public static final String DEFAULT_BROWSER_PROMO_SESSION_COUNT =
|
||||
"Chrome.DefaultBrowserPromo.SessionCount";
|
||||
public static final String DEFAULT_BROWSER_PROMO_IS_PROMOED =
|
||||
"Chrome.DefaultBrowserPromo.IsPromoed";
|
||||
|
||||
public static final String DOWNLOAD_AUTO_RESUMPTION_ATTEMPT_LEFT = "ResumptionAttemptLeft";
|
||||
public static final String DOWNLOAD_FOREGROUND_SERVICE_OBSERVERS = "ForegroundServiceObservers";
|
||||
public static final String DOWNLOAD_IS_DOWNLOAD_HOME_ENABLED =
|
||||
@ -761,6 +769,8 @@ public final class ChromePreferenceKeys {
|
||||
CONTEXT_MENU_OPEN_IN_EPHEMERAL_TAB_CLICKED,
|
||||
CONTEXT_MENU_SEARCH_WITH_GOOGLE_LENS_CLICKED,
|
||||
CRYPTID_LAST_RENDER_TIMESTAMP,
|
||||
DEFAULT_BROWSER_PROMO_IS_PROMOED,
|
||||
DEFAULT_BROWSER_PROMO_SESSION_COUNT,
|
||||
EXPLORE_OFFLINE_CONTENT_AVAILABILITY_STATUS,
|
||||
FLAGS_CACHED.pattern(),
|
||||
FLAGS_CACHED_DUET_TABSTRIP_INTEGRATION_ANDROID_ENABLED,
|
||||
|
73
chrome/browser/ui/android/default_browser_promo/BUILD.gn
Normal file
73
chrome/browser/ui/android/default_browser_promo/BUILD.gn
Normal file
@ -0,0 +1,73 @@
|
||||
# Copyright 2020 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.
|
||||
|
||||
import("//build/config/android/rules.gni")
|
||||
|
||||
android_library("java") {
|
||||
sources = [
|
||||
"java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoDialog.java",
|
||||
"java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManager.java",
|
||||
"java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtils.java",
|
||||
]
|
||||
deps = [
|
||||
":java_resources",
|
||||
"//base:base_java",
|
||||
"//chrome/browser/flags:java",
|
||||
"//chrome/browser/preferences:java",
|
||||
"//chrome/browser/profiles/android:java",
|
||||
"//components/browser_ui/widget/android:java",
|
||||
]
|
||||
}
|
||||
|
||||
android_resources("java_resources") {
|
||||
custom_package = "org.chromium.chrome.browser.ui.default_browser_promo"
|
||||
sources = [
|
||||
"java/res/drawable/default_browser_promo_illustration.xml",
|
||||
"java/res/drawable/ic_illustration_aroundlogo.xml",
|
||||
]
|
||||
deps = [
|
||||
"//chrome/browser/ui/android/strings:ui_strings_grd",
|
||||
"//components/browser_ui/widget/android:java_resources",
|
||||
"//ui/android:ui_java_resources",
|
||||
]
|
||||
}
|
||||
|
||||
java_library("junit") {
|
||||
# Skip platform checks since Robolectric depends on requires_android targets.
|
||||
bypass_platform_checks = true
|
||||
testonly = true
|
||||
sources = [ "java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java" ]
|
||||
deps = [
|
||||
":java",
|
||||
"//base:base_java",
|
||||
"//base:base_junit_test_support",
|
||||
"//third_party/android_deps:robolectric_all_java",
|
||||
"//third_party/junit",
|
||||
"//third_party/mockito:mockito_java",
|
||||
]
|
||||
}
|
||||
|
||||
android_library("javatests") {
|
||||
testonly = true
|
||||
|
||||
sources = [ "java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManagerTest.java" ]
|
||||
|
||||
deps = [
|
||||
":java",
|
||||
"//base:base_java",
|
||||
"//base:base_java_test_support",
|
||||
"//chrome/android:chrome_java",
|
||||
"//chrome/test/android:chrome_java_test_support",
|
||||
"//components/browser_ui/widget/android:java",
|
||||
"//content/public/test/android:content_java_test_support",
|
||||
"//third_party/android_deps:android_support_v7_appcompat_java",
|
||||
"//third_party/android_deps:androidx_preference_preference_java",
|
||||
"//third_party/android_deps:espresso_java",
|
||||
"//third_party/android_support_test_runner:rules_java",
|
||||
"//third_party/android_support_test_runner:runner_java",
|
||||
"//third_party/hamcrest:hamcrest_java",
|
||||
"//third_party/junit:junit",
|
||||
"//ui/android:ui_java_test_support",
|
||||
]
|
||||
}
|
12
chrome/browser/ui/android/default_browser_promo/DEPS
Normal file
12
chrome/browser/ui/android/default_browser_promo/DEPS
Normal file
@ -0,0 +1,12 @@
|
||||
noparent = True
|
||||
include_rules = [
|
||||
"+base/android",
|
||||
"+base/test/android",
|
||||
"+content/public/test/android",
|
||||
"+chrome/browser/flags",
|
||||
"+chrome/browser/profiles/android",
|
||||
"+chrome/browser/preferences",
|
||||
"+chrome/test/android",
|
||||
"+components/browser_ui/widget/android",
|
||||
"+ui/android",
|
||||
]
|
6
chrome/browser/ui/android/default_browser_promo/OWNERS
Normal file
6
chrome/browser/ui/android/default_browser_promo/OWNERS
Normal file
@ -0,0 +1,6 @@
|
||||
lazzzis@google.com
|
||||
twellington@chromium.org
|
||||
|
||||
# TEAM: chrome-android-app@chromium.org
|
||||
# COMPONENT: UI>Browser>Mobile>Messages
|
||||
# OS: Android
|
17
chrome/browser/ui/android/default_browser_promo/java/res/drawable/default_browser_promo_illustration.xml
Normal file
17
chrome/browser/ui/android/default_browser_promo/java/res/drawable/default_browser_promo_illustration.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2020 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. -->
|
||||
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:height="122dp"
|
||||
android:width="127dp"
|
||||
android:drawable="@drawable/ic_illustration_aroundlogo" />
|
||||
<item
|
||||
android:top="27dp"
|
||||
android:left="27dp"
|
||||
android:height="65dp"
|
||||
android:width="65dp"
|
||||
android:drawable="@mipmap/app_icon"/>
|
||||
</layer-list>
|
75
chrome/browser/ui/android/default_browser_promo/java/res/drawable/ic_illustration_aroundlogo.xml
Normal file
75
chrome/browser/ui/android/default_browser_promo/java/res/drawable/ic_illustration_aroundlogo.xml
Normal file
File diff suppressed because one or more lines are too long
123
chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoDialog.java
Normal file
123
chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoDialog.java
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright 2020 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.ui.default_browser_promo;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import org.chromium.base.BuildInfo;
|
||||
import org.chromium.components.browser_ui.widget.PromoDialog;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* The promo dialog guiding how to set Chrome as the default browser.
|
||||
*/
|
||||
public class DefaultBrowserPromoDialog extends PromoDialog {
|
||||
@IntDef({DialogStyle.ROLE_MANAGER, DialogStyle.DISAMBIGUATION_SHEET,
|
||||
DialogStyle.SYSTEM_SETTINGS})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DialogStyle {
|
||||
int ROLE_MANAGER = 0;
|
||||
int DISAMBIGUATION_SHEET = 1;
|
||||
int SYSTEM_SETTINGS = 2;
|
||||
}
|
||||
|
||||
private final int mDialogStyle;
|
||||
private final Runnable mOnOK;
|
||||
private Runnable mOnCancel;
|
||||
|
||||
/**
|
||||
* Building a {@link DefaultBrowserPromoDialog}.
|
||||
* @param activity The activity to display dialog.
|
||||
* @param dialogStyle The type of dialog.
|
||||
* @param onOK The {@link Runnable} on user's agreeing to change default.
|
||||
* @param onCancel The {@link Runnable} on user's refusing or dismissing the dialog.
|
||||
* @return
|
||||
*/
|
||||
public static DefaultBrowserPromoDialog createDialog(
|
||||
Activity activity, @DialogStyle int dialogStyle, Runnable onOK, Runnable onCancel) {
|
||||
return new DefaultBrowserPromoDialog(activity, dialogStyle, onOK, onCancel);
|
||||
}
|
||||
|
||||
private DefaultBrowserPromoDialog(
|
||||
Activity activity, @DialogStyle int style, Runnable onOK, Runnable onCancel) {
|
||||
super(activity);
|
||||
mDialogStyle = style;
|
||||
mOnOK = onOK;
|
||||
mOnCancel = onCancel;
|
||||
setOnDismissListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibleForTesting
|
||||
public DialogParams getDialogParams() {
|
||||
DialogParams params = new DialogParams();
|
||||
|
||||
Activity activity = getOwnerActivity();
|
||||
assert activity != null;
|
||||
|
||||
String appName = BuildInfo.getInstance().hostPackageLabel;
|
||||
params.vectorDrawableResource = R.drawable.default_browser_promo_illustration;
|
||||
params.headerCharSequence =
|
||||
activity.getString(R.string.default_browser_promo_dialog_title, appName);
|
||||
String desc =
|
||||
activity.getString(R.string.default_browser_promo_dialog_desc, appName) + "\n\n";
|
||||
String steps;
|
||||
String primaryButtonText;
|
||||
if (mDialogStyle == DialogStyle.ROLE_MANAGER) {
|
||||
steps = activity.getString(
|
||||
R.string.default_browser_promo_dialog_role_manager_steps, appName);
|
||||
primaryButtonText = activity.getString(
|
||||
R.string.default_browser_promo_dialog_choose_chrome_button, appName);
|
||||
} else if (mDialogStyle == DialogStyle.DISAMBIGUATION_SHEET) {
|
||||
steps = activity.getString(
|
||||
R.string.default_browser_promo_dialog_disambiguation_sheet_steps, appName);
|
||||
primaryButtonText = activity.getString(
|
||||
R.string.default_browser_promo_dialog_choose_chrome_button, appName);
|
||||
} else {
|
||||
assert mDialogStyle == DialogStyle.SYSTEM_SETTINGS;
|
||||
steps = activity.getString(
|
||||
R.string.default_browser_promo_dialog_system_settings_steps, appName);
|
||||
primaryButtonText =
|
||||
activity.getString(R.string.default_browser_promo_dialog_go_to_settings_button);
|
||||
}
|
||||
params.subheaderCharSequence = desc + steps;
|
||||
params.primaryButtonCharSequence = primaryButtonText;
|
||||
params.secondaryButtonStringResource = R.string.no_thanks;
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
// Can be dismissed by pressing the back button.
|
||||
if (mOnCancel != null) mOnCancel.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
super.onClick(view);
|
||||
int id = view.getId();
|
||||
if (id == R.id.button_primary) {
|
||||
mOnCancel = null;
|
||||
mOnOK.run();
|
||||
dismiss();
|
||||
} else if (id == R.id.button_secondary) {
|
||||
if (mOnCancel != null) mOnCancel.run();
|
||||
mOnCancel = null;
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public int getDialogStyleForTesting() {
|
||||
return mDialogStyle;
|
||||
}
|
||||
}
|
103
chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManager.java
Normal file
103
chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManager.java
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2020 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.ui.default_browser_promo;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.role.RoleManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Manage all types of default browser promo dialogs and listen to the activity state change to
|
||||
* trigger dialogs.
|
||||
*/
|
||||
public class DefaultBrowserPromoManager {
|
||||
private final Activity mActivity;
|
||||
private DefaultBrowserPromoDialog mDialog;
|
||||
|
||||
/**
|
||||
* @param activity Activity to show promo dialogs.
|
||||
* @return A {@link DefaultBrowserPromoManager} displaying dialogs based on android version and
|
||||
* current default browser state in system.
|
||||
*/
|
||||
public static DefaultBrowserPromoManager create(Activity activity) {
|
||||
return new DefaultBrowserPromoManager(activity);
|
||||
}
|
||||
|
||||
private DefaultBrowserPromoManager(Activity activity) {
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param state The current {@link DefaultBrowserPromoUtils.DefaultBrowserState} in system.
|
||||
*/
|
||||
public void promo(@DefaultBrowserPromoUtils.DefaultBrowserState int state) {
|
||||
promoInternal(state, Build.VERSION.SDK_INT);
|
||||
}
|
||||
|
||||
private void promoInternal(
|
||||
@DefaultBrowserPromoUtils.DefaultBrowserState int state, int sdkInt) {
|
||||
if (sdkInt >= Build.VERSION_CODES.Q) {
|
||||
promoByRoleManager();
|
||||
} else if (state == DefaultBrowserPromoUtils.DefaultBrowserState.NO_DEFAULT) {
|
||||
promoByDisambiguationSheet();
|
||||
} else if (sdkInt >= Build.VERSION_CODES.M) {
|
||||
promoBySystemSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint({"WrongConstant", "NewApi"})
|
||||
private void promoByRoleManager() {
|
||||
showDialog(DefaultBrowserPromoDialog.DialogStyle.ROLE_MANAGER, () -> {
|
||||
RoleManager roleManager =
|
||||
(RoleManager) mActivity.getSystemService(Context.ROLE_SERVICE);
|
||||
boolean isRoleAvailable = roleManager.isRoleAvailable(RoleManager.ROLE_BROWSER);
|
||||
boolean isRoleHeld = roleManager.isRoleHeld(RoleManager.ROLE_BROWSER);
|
||||
|
||||
// TODO(crbug.com/1090103): check the condition before deciding
|
||||
// to show promo and remove the assertion.
|
||||
assert isRoleAvailable && !isRoleHeld;
|
||||
|
||||
Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_BROWSER);
|
||||
mActivity.startActivityForResult(intent, 0);
|
||||
});
|
||||
}
|
||||
|
||||
private void promoBySystemSettings() {
|
||||
showDialog(DefaultBrowserPromoDialog.DialogStyle.SYSTEM_SETTINGS, () -> {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS);
|
||||
mActivity.startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
||||
private void promoByDisambiguationSheet() {
|
||||
showDialog(DefaultBrowserPromoDialog.DialogStyle.DISAMBIGUATION_SHEET, () -> {
|
||||
Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||
intent.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||
mActivity.startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
||||
private void showDialog(@DefaultBrowserPromoDialog.DialogStyle int style, Runnable okCallback) {
|
||||
mDialog = DefaultBrowserPromoDialog.createDialog(mActivity, style, okCallback, null);
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public DefaultBrowserPromoDialog getDialogForTesting() {
|
||||
return mDialog;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void promoForTesting(
|
||||
@DefaultBrowserPromoUtils.DefaultBrowserState int state, int sdkInt) {
|
||||
promoInternal(state, sdkInt);
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
// Copyright 2020 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.ui.default_browser_promo;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
|
||||
import androidx.test.filters.MediumTest;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.chromium.base.BuildInfo;
|
||||
import org.chromium.base.test.util.CommandLineFlags;
|
||||
import org.chromium.chrome.R;
|
||||
import org.chromium.chrome.browser.flags.ChromeSwitches;
|
||||
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
|
||||
import org.chromium.components.browser_ui.widget.PromoDialog;
|
||||
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||
import org.chromium.ui.test.util.DummyUiActivity;
|
||||
|
||||
/**
|
||||
* Instrument test for {@link DefaultBrowserPromoManager}.
|
||||
*/
|
||||
@RunWith(ChromeJUnit4ClassRunner.class)
|
||||
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
|
||||
public class DefaultBrowserPromoManagerTest {
|
||||
@Rule
|
||||
public ActivityTestRule<DummyUiActivity> mRule = new ActivityTestRule<>(DummyUiActivity.class);
|
||||
|
||||
private DefaultBrowserPromoManager mManager;
|
||||
private Activity mActivity;
|
||||
private String mAppName;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mActivity = mRule.getActivity();
|
||||
mManager = DefaultBrowserPromoManager.create(mActivity);
|
||||
mAppName = BuildInfo.getInstance().hostPackageLabel;
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
public void testPromoByRoleManager() {
|
||||
TestThreadUtils.runOnUiThreadBlocking(() -> {
|
||||
mManager.promoForTesting(
|
||||
DefaultBrowserPromoUtils.DefaultBrowserState.NO_DEFAULT, Build.VERSION_CODES.Q);
|
||||
});
|
||||
DefaultBrowserPromoDialog dialog = mManager.getDialogForTesting();
|
||||
Assert.assertEquals("Dialog should be of role manager style on Q+",
|
||||
dialog.getDialogStyleForTesting(),
|
||||
DefaultBrowserPromoDialog.DialogStyle.ROLE_MANAGER);
|
||||
|
||||
// test role manager style
|
||||
PromoDialog.DialogParams params = dialog.getDialogParams();
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(R.string.default_browser_promo_dialog_title, mAppName),
|
||||
params.headerCharSequence);
|
||||
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(R.string.default_browser_promo_dialog_desc, mAppName) + "\n\n"
|
||||
+ mActivity.getString(
|
||||
R.string.default_browser_promo_dialog_role_manager_steps, mAppName),
|
||||
params.subheaderCharSequence);
|
||||
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(
|
||||
R.string.default_browser_promo_dialog_choose_chrome_button, mAppName),
|
||||
params.primaryButtonCharSequence);
|
||||
|
||||
checkDialogVisibility();
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
public void testPromoBySystemSettingsOnL() {
|
||||
TestThreadUtils.runOnUiThreadBlocking(() -> {
|
||||
mManager.promoForTesting(DefaultBrowserPromoUtils.DefaultBrowserState.OTHER_DEFAULT,
|
||||
Build.VERSION_CODES.LOLLIPOP);
|
||||
});
|
||||
DefaultBrowserPromoDialog dialog = mManager.getDialogForTesting();
|
||||
|
||||
Assert.assertNull("Dialog of system settings style should not be displayed on L", dialog);
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
public void testPromoBySystemSettingsOnP() {
|
||||
TestThreadUtils.runOnUiThreadBlocking(() -> {
|
||||
mManager.promoForTesting(DefaultBrowserPromoUtils.DefaultBrowserState.OTHER_DEFAULT,
|
||||
Build.VERSION_CODES.P);
|
||||
});
|
||||
DefaultBrowserPromoDialog dialog = mManager.getDialogForTesting();
|
||||
Assert.assertEquals(
|
||||
"Dialog should be of system settings style on P-, when there is another default in system",
|
||||
dialog.getDialogStyleForTesting(),
|
||||
DefaultBrowserPromoDialog.DialogStyle.SYSTEM_SETTINGS);
|
||||
|
||||
// test role manager style
|
||||
PromoDialog.DialogParams params = dialog.getDialogParams();
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(R.string.default_browser_promo_dialog_title, mAppName),
|
||||
params.headerCharSequence);
|
||||
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(R.string.default_browser_promo_dialog_desc, mAppName) + "\n\n"
|
||||
+ mActivity.getString(
|
||||
R.string.default_browser_promo_dialog_system_settings_steps,
|
||||
mAppName),
|
||||
params.subheaderCharSequence);
|
||||
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(R.string.default_browser_promo_dialog_go_to_settings_button),
|
||||
params.primaryButtonCharSequence);
|
||||
|
||||
checkDialogVisibility();
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
public void testPromoByDisambiguationSheet() {
|
||||
TestThreadUtils.runOnUiThreadBlocking(() -> {
|
||||
mManager.promoForTesting(
|
||||
DefaultBrowserPromoUtils.DefaultBrowserState.NO_DEFAULT, Build.VERSION_CODES.P);
|
||||
});
|
||||
DefaultBrowserPromoDialog dialog = mManager.getDialogForTesting();
|
||||
Assert.assertEquals(
|
||||
"Dialog should be of disambiguation sheet style on P-, when there is no default in system",
|
||||
dialog.getDialogStyleForTesting(),
|
||||
DefaultBrowserPromoDialog.DialogStyle.DISAMBIGUATION_SHEET);
|
||||
|
||||
// test role manager style
|
||||
PromoDialog.DialogParams params = dialog.getDialogParams();
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(R.string.default_browser_promo_dialog_title, mAppName),
|
||||
params.headerCharSequence);
|
||||
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(R.string.default_browser_promo_dialog_desc, mAppName) + "\n\n"
|
||||
+ mActivity.getString(
|
||||
R.string.default_browser_promo_dialog_disambiguation_sheet_steps,
|
||||
mAppName),
|
||||
params.subheaderCharSequence);
|
||||
|
||||
Assert.assertEquals(
|
||||
mActivity.getString(
|
||||
R.string.default_browser_promo_dialog_choose_chrome_button, mAppName),
|
||||
params.primaryButtonCharSequence);
|
||||
|
||||
checkDialogVisibility();
|
||||
}
|
||||
|
||||
private void checkDialogVisibility() {
|
||||
onView(withId(R.id.promo_dialog_layout)).check(matches(isDisplayed()));
|
||||
// dismiss the dialog
|
||||
onView(withId(R.id.button_secondary)).perform(click());
|
||||
onView(withId(R.id.promo_dialog_layout)).check((v, noMatchingViewException) -> {
|
||||
Assert.assertNotNull("Promo dialog should be dismissed by clicking on secondary button",
|
||||
noMatchingViewException);
|
||||
});
|
||||
}
|
||||
}
|
153
chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtils.java
Normal file
153
chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtils.java
Normal file
@ -0,0 +1,153 @@
|
||||
// Copyright 2020 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.ui.default_browser_promo;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
import org.chromium.base.ContextUtils;
|
||||
import org.chromium.base.PackageManagerUtils;
|
||||
import org.chromium.chrome.browser.flags.ChromeFeatureList;
|
||||
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
|
||||
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* A utility class providing information regarding states of default browser.
|
||||
*/
|
||||
public class DefaultBrowserPromoUtils {
|
||||
@IntDef({DefaultBrowserState.CHROME_DEFAULT, DefaultBrowserState.NO_DEFAULT,
|
||||
DefaultBrowserState.OTHER_DEFAULT})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DefaultBrowserState {
|
||||
int NO_DEFAULT = 0;
|
||||
int OTHER_DEFAULT = 1;
|
||||
/**
|
||||
* CHROME_DEFAULT means the currently running Chrome as opposed to
|
||||
* #isCurrentDefaultBrowserChrome() which looks for any Chrome.
|
||||
*/
|
||||
int CHROME_DEFAULT = 2;
|
||||
}
|
||||
|
||||
private static final int MIN_TRIGGER_SESSION_COUNT = 3;
|
||||
private static final String SESSION_COUNT_PARAM = "min_trigger_session_count";
|
||||
|
||||
private static final String CHROME_STABLE_PACKAGE_NAME = "com.android.chrome";
|
||||
|
||||
// TODO(crbug.com/1090103): move to some util class for reuse.
|
||||
private static final String[] CHROME_PACKAGE_NAMES = {CHROME_STABLE_PACKAGE_NAME,
|
||||
"org.chromium.chrome", "com.chrome.canary", "com.chrome.beta", "com.chrome.dev"};
|
||||
|
||||
/**
|
||||
* Determine whether a promo dialog should be displayed or not. And prepare related logic to
|
||||
* launch promo if a promo dialog has been decided to display.
|
||||
* Return false if any of following criteria is met:
|
||||
* 1. A promo dialog has been displayed before.
|
||||
* 2. Not enough sessions have been started before.
|
||||
* 3. Any chrome, including pre-stable, has been set as default.
|
||||
* 4. On Chrome stable while no default browser is set and multiple chrome channels
|
||||
* are installed.
|
||||
*
|
||||
* @param activity The context.
|
||||
* @return True if promo dialog will be displayed.
|
||||
*/
|
||||
public static boolean prepareLaunchPromoIfNeeded(Activity activity) {
|
||||
if (!ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_DEFAULT_BROWSER_PROMO)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Criteria 1
|
||||
// TODO(crbug.com/1090103): change to int if dialog will be re-promo.
|
||||
if (SharedPreferencesManager.getInstance().readBoolean(
|
||||
ChromePreferenceKeys.DEFAULT_BROWSER_PROMO_IS_PROMOED, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Criteria 2
|
||||
int minSessionCount = ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
|
||||
ChromeFeatureList.ANDROID_DEFAULT_BROWSER_PROMO, SESSION_COUNT_PARAM,
|
||||
MIN_TRIGGER_SESSION_COUNT);
|
||||
|
||||
if (SharedPreferencesManager.getInstance().readInt(
|
||||
ChromePreferenceKeys.DEFAULT_BROWSER_PROMO_SESSION_COUNT, 0)
|
||||
< minSessionCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResolveInfo info = PackageManagerUtils.resolveDefaultWebBrowserActivity();
|
||||
int state = getCurrentDefaultBrowserState(info);
|
||||
|
||||
// Already default
|
||||
if (state == DefaultBrowserState.CHROME_DEFAULT) return false;
|
||||
|
||||
// Criteria 3
|
||||
if (state == DefaultBrowserState.OTHER_DEFAULT && isCurrentDefaultBrowserChrome(info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Criteria 4
|
||||
if (ContextUtils.getApplicationContext().getPackageName().equals(CHROME_STABLE_PACKAGE_NAME)
|
||||
&& isChromePreStableInstalled()
|
||||
&& state == DefaultBrowserState.NO_DEFAULT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedPreferencesManager.getInstance().writeBoolean(
|
||||
ChromePreferenceKeys.DEFAULT_BROWSER_PROMO_IS_PROMOED, true);
|
||||
DefaultBrowserPromoManager.create(activity).promo(state);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment session count for triggering feature in the future.
|
||||
*/
|
||||
public static void incrementSessionCount() {
|
||||
if (!ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_DEFAULT_BROWSER_PROMO)) return;
|
||||
SharedPreferencesManager.getInstance().incrementInt(
|
||||
ChromePreferenceKeys.DEFAULT_BROWSER_PROMO_SESSION_COUNT);
|
||||
}
|
||||
|
||||
private static boolean isChromePreStableInstalled() {
|
||||
for (ResolveInfo info : PackageManagerUtils.queryAllWebBrowsersInfo()) {
|
||||
for (String name : CHROME_PACKAGE_NAMES) {
|
||||
if (name.equals(CHROME_STABLE_PACKAGE_NAME)) continue;
|
||||
if (name.equals(info.activityInfo.packageName)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isCurrentDefaultBrowserChrome(ResolveInfo info) {
|
||||
String packageName = info.activityInfo.packageName;
|
||||
for (String name : CHROME_PACKAGE_NAMES) {
|
||||
if (name.equals(packageName)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@DefaultBrowserState
|
||||
private static int getCurrentDefaultBrowserState(ResolveInfo info) {
|
||||
if (info.match == 0) return DefaultBrowserState.NO_DEFAULT; // no default
|
||||
if (TextUtils.equals(ContextUtils.getApplicationContext().getPackageName(),
|
||||
info.activityInfo.packageName)) {
|
||||
return DefaultBrowserState.CHROME_DEFAULT; // Already default
|
||||
}
|
||||
return DefaultBrowserState.OTHER_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current {@link DefaultBrowserState} in the system.
|
||||
*/
|
||||
@DefaultBrowserState
|
||||
public static int getCurrentDefaultBrowserState() {
|
||||
ResolveInfo info = PackageManagerUtils.resolveDefaultWebBrowserActivity();
|
||||
return getCurrentDefaultBrowserState(info);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
// Copyright 2020 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.ui.default_browser_promo;
|
||||
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowPackageManager;
|
||||
|
||||
import org.chromium.base.ContextUtils;
|
||||
import org.chromium.base.PackageManagerUtils;
|
||||
import org.chromium.base.test.BaseRobolectricTestRunner;
|
||||
|
||||
/**
|
||||
* Unit test for {@link DefaultBrowserPromoUtils}.
|
||||
*/
|
||||
@RunWith(BaseRobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class DefaultBrowserPromoUtilsTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1090103): Add test for No Default case and other helper methods in
|
||||
// DefaultBrowserPromoUtils.
|
||||
// ResolveInfo#match is changed when intent is resolved, even if we mock it to 0 here.
|
||||
|
||||
@Test
|
||||
public void testGetCurrentDefaultStateForOtherDefault() {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
resolveInfo.match = 1;
|
||||
activityInfo.packageName = "android";
|
||||
resolveInfo.activityInfo = activityInfo;
|
||||
ShadowPackageManager packageManager =
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager());
|
||||
packageManager.addResolveInfoForIntent(
|
||||
PackageManagerUtils.getQueryInstalledBrowsersIntent(), resolveInfo);
|
||||
Assert.assertEquals("Should be other default when resolve info matches another browser.",
|
||||
DefaultBrowserPromoUtils.DefaultBrowserState.OTHER_DEFAULT,
|
||||
DefaultBrowserPromoUtils.getCurrentDefaultBrowserState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCurrentDefaultStateForChromeDefault() {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
resolveInfo.match = 1;
|
||||
activityInfo.packageName = ContextUtils.getApplicationContext().getPackageName();
|
||||
resolveInfo.activityInfo = activityInfo;
|
||||
ShadowPackageManager packageManager =
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager());
|
||||
packageManager.addResolveInfoForIntent(
|
||||
PackageManagerUtils.getQueryInstalledBrowsersIntent(), resolveInfo);
|
||||
Assert.assertEquals(
|
||||
"Should be chrome default when resolve info matches current package name.",
|
||||
DefaultBrowserPromoUtils.DefaultBrowserState.CHROME_DEFAULT,
|
||||
DefaultBrowserPromoUtils.getCurrentDefaultBrowserState());
|
||||
}
|
||||
}
|
@ -3727,6 +3727,31 @@ To change this setting, <ph name="BEGIN_LINK"><resetlink></ph>reset sync<p
|
||||
<message name="IDS_PAINT_PREVIEW_DEMO_PLAYBACK_FAILURE" desc="Toast message displayed when there is a failure in playing back a paint preview for the demo. Used in paint preview demo mode." translateable="false">
|
||||
Paint Preview playback failed.
|
||||
</message>
|
||||
|
||||
<!-- Default Browser Promo Strings-->
|
||||
<message name="IDS_DEFAULT_BROWSER_PROMO_DIALOG_TITLE" desc="Title of the default browser promo dialog">
|
||||
Set <ph name="APP_NAME">%1$s<ex>Chrome</ex></ph> as your default?
|
||||
</message>
|
||||
<message name="IDS_DEFAULT_BROWSER_PROMO_DIALOG_DESC" desc="Description in the default browser promo dialog, which is concatenated with one of the following steps strings">
|
||||
<ph name="APP_NAME">%1$s<ex>Chrome</ex></ph> has the smarts and speed you need to safely do, create, and explore online
|
||||
</message>
|
||||
<message name="IDS_DEFAULT_BROWSER_PROMO_DIALOG_DISAMBIGUATION_SHEET_STEPS" desc="Description of the steps to set the default browser throught disambiguation sheet. 'Always' should match TC ID 4089537686339013930.">
|
||||
1. Choose <ph name="APP_NAME">%1$s<ex>Chrome</ex></ph>\n2. Tap “Always”
|
||||
</message>
|
||||
<message name="IDS_DEFAULT_BROWSER_PROMO_DIALOG_SYSTEM_SETTINGS_STEPS"
|
||||
desc="Description of the steps to set the default browser throught system settings.
|
||||
'Go to Settings' should match TC ID 4431460803004659888. 'Browser App' should match TC ID 6222206565850006894.">
|
||||
1. Go to Settings\n2. Tap “Browser App”\n3. Choose <ph name="APP_NAME">%1$s<ex>Chrome</ex></ph>
|
||||
</message>
|
||||
<message name="IDS_DEFAULT_BROWSER_PROMO_DIALOG_ROLE_MANAGER_STEPS" desc="Description of the steps to set the default browser throught role manager. 'Set as default' should match TC ID 5706081295230541240.">
|
||||
1. Choose <ph name="APP_NAME">%1$s<ex>Chrome</ex></ph>\n2. Tap “Set as default”
|
||||
</message>
|
||||
<message name="IDS_DEFAULT_BROWSER_PROMO_DIALOG_CHOOSE_CHROME_BUTTON" desc="A button in the default browser promo dialog to choose chrome as default">
|
||||
Choose <ph name="APP_NAME">%1$s<ex>Chrome</ex></ph>
|
||||
</message>
|
||||
<message name="IDS_DEFAULT_BROWSER_PROMO_DIALOG_GO_TO_SETTINGS_BUTTON" desc="A button in the default browser promo to navigate users to systen settings. 'Go to Settings' should match TC ID 4431460803004659888.">
|
||||
Go to Settings
|
||||
</message>
|
||||
</messages>
|
||||
</release>
|
||||
</grit>
|
||||
|
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_CHOOSE_CHROME_BUTTON.png.sha1
Normal file
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_CHOOSE_CHROME_BUTTON.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
bb6d6d6f68515ff14ec7342be489930390f042e9
|
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_DESC.png.sha1
Normal file
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_DESC.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
bb6d6d6f68515ff14ec7342be489930390f042e9
|
@ -0,0 +1 @@
|
||||
9eacef949b483b14f39203a91cf344fc1b411308
|
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_GO_TO_SETTINGS_BUTTON.png.sha1
Normal file
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_GO_TO_SETTINGS_BUTTON.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
16654f05aa1fd22112a0a2fe8acc19c9e7a90e25
|
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_ROLE_MANAGER_STEPS.png.sha1
Normal file
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_ROLE_MANAGER_STEPS.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
bb6d6d6f68515ff14ec7342be489930390f042e9
|
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_SYSTEM_SETTINGS_STEPS.png.sha1
Normal file
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_SYSTEM_SETTINGS_STEPS.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
16654f05aa1fd22112a0a2fe8acc19c9e7a90e25
|
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_TITLE.png.sha1
Normal file
1
chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DEFAULT_BROWSER_PROMO_DIALOG_TITLE.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
bb6d6d6f68515ff14ec7342be489930390f042e9
|
@ -16,7 +16,7 @@
|
||||
<!-- Dialogs -->
|
||||
<dimen name="dialog_max_width">600dp</dimen>
|
||||
<dimen name="dialog_header_margin">14dp</dimen>
|
||||
<dimen name="promo_dialog_illustration_margin">24dp</dimen>
|
||||
<dimen name="promo_dialog_illustration_margin">8dp</dimen>
|
||||
<dimen name="promo_dialog_illustration_width">150dp</dimen>
|
||||
<dimen name="promo_dialog_padding">16dp</dimen>
|
||||
<dimen name="promo_dialog_stacked_margin">16dp</dimen>
|
||||
|
@ -49,6 +49,12 @@ public abstract class PromoDialog extends AlwaysDismissedDialog
|
||||
/** Resource ID of the String to show as the promo title. */
|
||||
public int headerStringResource;
|
||||
|
||||
/**
|
||||
* Optional: CharSequence to show as promo title.
|
||||
* This parameter takes precedence over {@link #headerStringResoruce}
|
||||
*/
|
||||
public CharSequence headerCharSequence;
|
||||
|
||||
/**
|
||||
* Optional: CharSequence to show as descriptive text.
|
||||
* This parameter takes precedence over {@link #subheaderStringResoruce}
|
||||
@ -67,6 +73,12 @@ public abstract class PromoDialog extends AlwaysDismissedDialog
|
||||
/** Optional: Resource ID of the String to show on the primary/ok button. */
|
||||
public int primaryButtonStringResource;
|
||||
|
||||
/**
|
||||
* Optional: CharSequence to show on the primary/ok button.
|
||||
* This parameter takes precedence over {@link #primaryButtonStringResource}
|
||||
*/
|
||||
public CharSequence primaryButtonCharSequence;
|
||||
|
||||
/** Optional: Resource ID of the String to show on the secondary/cancel button. */
|
||||
public int secondaryButtonStringResource;
|
||||
}
|
||||
@ -74,7 +86,7 @@ public abstract class PromoDialog extends AlwaysDismissedDialog
|
||||
private static final int[] CLICKABLE_BUTTON_IDS = {R.id.button_primary, R.id.button_secondary};
|
||||
|
||||
private final FrameLayout mScrimView;
|
||||
private final PromoDialogLayout mDialogLayout;
|
||||
private PromoDialogLayout mDialogLayout;
|
||||
|
||||
protected PromoDialog(Activity activity) {
|
||||
super(activity, R.style.PromoDialog);
|
||||
@ -85,7 +97,6 @@ public abstract class PromoDialog extends AlwaysDismissedDialog
|
||||
LayoutInflater.from(activity).inflate(R.layout.promo_dialog_layout, mScrimView, true);
|
||||
|
||||
mDialogLayout = (PromoDialogLayout) mScrimView.findViewById(R.id.promo_dialog_layout);
|
||||
mDialogLayout.initialize(getDialogParams());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,6 +123,8 @@ public abstract class PromoDialog extends AlwaysDismissedDialog
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(mScrimView);
|
||||
|
||||
mDialogLayout.initialize(getDialogParams());
|
||||
|
||||
// Force the window to allow the dialog contents be as wide as necessary.
|
||||
getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
|
||||
|
@ -81,8 +81,8 @@ public final class PromoDialogLayout extends BoundedLinearLayout {
|
||||
/** Initializes the dialog contents using the given params. Should only be called once. */
|
||||
void initialize(DialogParams params) {
|
||||
assert mParams == null && params != null;
|
||||
assert params.headerStringResource != 0;
|
||||
assert params.primaryButtonStringResource != 0;
|
||||
assert params.headerStringResource != 0 || params.headerCharSequence != null;
|
||||
assert params.primaryButtonStringResource != 0 || params.primaryButtonCharSequence != null;
|
||||
mParams = params;
|
||||
|
||||
if (mParams.drawableInstance != null) {
|
||||
@ -99,7 +99,11 @@ public final class PromoDialogLayout extends BoundedLinearLayout {
|
||||
}
|
||||
|
||||
// Create the header.
|
||||
mHeaderView.setText(mParams.headerStringResource);
|
||||
if (mParams.headerCharSequence != null) {
|
||||
mHeaderView.setText(mParams.headerCharSequence);
|
||||
} else {
|
||||
mHeaderView.setText(mParams.headerStringResource);
|
||||
}
|
||||
|
||||
// Set up the subheader text.
|
||||
if (mParams.subheaderCharSequence != null) {
|
||||
@ -124,7 +128,9 @@ public final class PromoDialogLayout extends BoundedLinearLayout {
|
||||
|
||||
// Create the buttons.
|
||||
DualControlLayout buttonBar = (DualControlLayout) findViewById(R.id.button_bar);
|
||||
String primaryString = getResources().getString(mParams.primaryButtonStringResource);
|
||||
String primaryString = mParams.primaryButtonCharSequence != null
|
||||
? mParams.primaryButtonCharSequence.toString()
|
||||
: getResources().getString(mParams.primaryButtonStringResource);
|
||||
buttonBar.addView(
|
||||
DualControlLayout.createButtonForLayout(getContext(), true, primaryString, null));
|
||||
|
||||
|
@ -38909,6 +38909,7 @@ from previous Chrome versions.
|
||||
<int value="-1859095876" label="Previews:disabled"/>
|
||||
<int value="-1858284725" label="TabGroupsFeedback:enabled"/>
|
||||
<int value="-1856902397" label="LoadingWithMojo:enabled"/>
|
||||
<int value="-1856718338" label="AndroidDefaultBrowserPromo:disabled"/>
|
||||
<int value="-1855347512" label="FormControlsRefresh:disabled"/>
|
||||
<int value="-1854432127" label="ChromeHomePullToRefreshIphAtTop:disabled"/>
|
||||
<int value="-1854372227" label="VrBrowsingExperimentalFeatures:enabled"/>
|
||||
@ -39242,6 +39243,7 @@ from previous Chrome versions.
|
||||
<int value="-1468126425" label="ResourceLoadScheduler:disabled"/>
|
||||
<int value="-1467642274" label="KeyboardShortcutViewer:disabled"/>
|
||||
<int value="-1467332609" label="tab-management-experiment-type-anise"/>
|
||||
<int value="-1467062925" label="AndroidDefaultBrowserPromo:enabled"/>
|
||||
<int value="-1466990325" label="CrosCompUpdates:enabled"/>
|
||||
<int value="-1466862366" label="TouchToFillAndroid:enabled"/>
|
||||
<int value="-1466759286" label="TabModalJsDialog:disabled"/>
|
||||
|
Reference in New Issue
Block a user