1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.locale; 6 7 import android.annotation.SuppressLint; 8 import android.app.Activity; 9 import android.content.DialogInterface; 10 import android.os.Bundle; 11 import android.widget.Button; 12 13 import androidx.annotation.Nullable; 14 import androidx.annotation.VisibleForTesting; 15 16 import org.chromium.base.Callback; 17 import org.chromium.base.metrics.RecordUserAction; 18 import org.chromium.chrome.R; 19 import org.chromium.chrome.browser.locale.LocaleManager.SearchEnginePromoType; 20 import org.chromium.components.browser_ui.widget.PromoDialog; 21 import org.chromium.components.browser_ui.widget.RadioButtonLayout; 22 23 /** A dialog that forces the user to choose a default search engine. */ 24 public class DefaultSearchEnginePromoDialog extends PromoDialog { 25 /** Notified about events happening to the dialog. */ 26 public static interface DefaultSearchEnginePromoDialogObserver { onDialogShown(DefaultSearchEnginePromoDialog shownDialog)27 void onDialogShown(DefaultSearchEnginePromoDialog shownDialog); 28 } 29 private static DefaultSearchEnginePromoDialogObserver sObserver; 30 31 @SuppressLint("StaticFieldLeak") 32 private static DefaultSearchEnginePromoDialog sCurrentDialog; 33 34 /** Used to determine the promo dialog contents. */ 35 @SearchEnginePromoType 36 private final int mDialogType; 37 38 /** Called when the dialog is dismissed after the user has chosen a search engine. */ 39 private final Callback<Boolean> mOnSuccessCallback; 40 41 /** Encapsulates most of the logic for filling the dialog and handling clicks. */ 42 private DefaultSearchEngineDialogHelper mHelper; 43 44 /** 45 * Construct the default search engine promo. 46 * 47 * @param activity Activity to build the dialog with. 48 * @param dialogType Type of dialog to show. 49 * @param onSuccessCallback Notified whether the user successfully chose a search engine and 50 * dismissed the dialog. 51 */ DefaultSearchEnginePromoDialog(Activity activity, @SearchEnginePromoType int dialogType, @Nullable Callback<Boolean> onSuccessCallback)52 DefaultSearchEnginePromoDialog(Activity activity, @SearchEnginePromoType int dialogType, 53 @Nullable Callback<Boolean> onSuccessCallback) { 54 super(activity); 55 mDialogType = dialogType; 56 mOnSuccessCallback = onSuccessCallback; 57 setOnDismissListener(this); 58 59 // No one should be able to bypass this dialog by clicking outside or by hitting back. 60 setCancelable(false); 61 setCanceledOnTouchOutside(false); 62 63 if (dialogType == LocaleManager.SearchEnginePromoType.SHOW_NEW) forceOpaqueBackground(); 64 } 65 66 @Override getDialogParams()67 protected DialogParams getDialogParams() { 68 PromoDialog.DialogParams params = new PromoDialog.DialogParams(); 69 params.headerStringResource = R.string.search_engine_dialog_title; 70 params.footerStringResource = R.string.search_engine_dialog_footer; 71 params.primaryButtonStringResource = R.string.ok; 72 return params; 73 } 74 75 @Override onCreate(Bundle savedInstanceState)76 protected void onCreate(Bundle savedInstanceState) { 77 super.onCreate(savedInstanceState); 78 79 Button okButton = (Button) findViewById(R.id.button_primary); 80 okButton.setEnabled(false); 81 82 RadioButtonLayout radioButtons = new RadioButtonLayout(getContext()); 83 radioButtons.setId(R.id.default_search_engine_dialog_options); 84 addControl(radioButtons); 85 86 Runnable dismissRunnable = new Runnable() { 87 @Override 88 public void run() { 89 dismiss(); 90 } 91 }; 92 mHelper = new DefaultSearchEngineDialogHelper( 93 mDialogType, radioButtons, okButton, dismissRunnable); 94 } 95 96 @Override show()97 public void show() { 98 super.show(); 99 if (sCurrentDialog != null) sCurrentDialog.dismiss(); 100 setCurrentDialog(this); 101 102 if (mDialogType == LocaleManager.SearchEnginePromoType.SHOW_NEW) { 103 RecordUserAction.record("SearchEnginePromo.NewDevice.Shown.Dialog"); 104 } else if (mDialogType == LocaleManager.SearchEnginePromoType.SHOW_EXISTING) { 105 RecordUserAction.record("SearchEnginePromo.ExistingDevice.Shown.Dialog"); 106 } 107 if (sObserver != null) sObserver.onDialogShown(this); 108 } 109 110 @Override onDismiss(DialogInterface dialog)111 public void onDismiss(DialogInterface dialog) { 112 if (mHelper.getConfirmedKeyword() == null) { 113 // If no selection, finish the Activity so that the user has to respond to the dialog 114 // next time. 115 if (getOwnerActivity() != null) getOwnerActivity().finish(); 116 } 117 118 if (mOnSuccessCallback != null) { 119 mOnSuccessCallback.onResult(mHelper.getConfirmedKeyword() != null); 120 } 121 122 if (sCurrentDialog == this) setCurrentDialog(null); 123 } 124 125 /** See {@link #sObserver}. */ 126 @VisibleForTesting setObserverForTests(DefaultSearchEnginePromoDialogObserver observer)127 public static void setObserverForTests(DefaultSearchEnginePromoDialogObserver observer) { 128 sObserver = observer; 129 } 130 131 /** @return The current visible Default Search Engine dialog. */ getCurrentDialog()132 static DefaultSearchEnginePromoDialog getCurrentDialog() { 133 return sCurrentDialog; 134 } 135 setCurrentDialog(DefaultSearchEnginePromoDialog dialog)136 private static void setCurrentDialog(DefaultSearchEnginePromoDialog dialog) { 137 sCurrentDialog = dialog; 138 } 139 } 140