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