Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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.content.Context; | |
| 8 import android.content.DialogInterface; | |
| 9 import android.os.Bundle; | |
| 10 import android.support.annotation.Nullable; | |
| 11 import android.view.View; | |
| 12 import android.widget.RadioButton; | |
| 13 import android.widget.RadioGroup; | |
| 14 import android.widget.RadioGroup.OnCheckedChangeListener; | |
| 15 | |
| 16 import org.chromium.base.library_loader.LibraryLoader; | |
| 17 import org.chromium.chrome.R; | |
| 18 import org.chromium.chrome.browser.infobar.InfoBarControlLayout; | |
| 19 import org.chromium.chrome.browser.search_engines.TemplateUrlService; | |
| 20 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl ; | |
| 21 import org.chromium.chrome.browser.widget.PromoDialog; | |
| 22 | |
| 23 import java.util.ArrayList; | |
| 24 import java.util.List; | |
| 25 import java.util.Random; | |
| 26 | |
| 27 /** A dialog that forces the user to choose a default search engine. */ | |
| 28 public class DefaultSearchEnginePromoDialog extends PromoDialog implements OnChe ckedChangeListener { | |
| 29 /** Used to determine the promo dialog contents. */ | |
| 30 private final int mDialogType; | |
| 31 | |
| 32 /** Run when the dialog is dismissed after the user has chosen a search engi ne. */ | |
| 33 private final Runnable mOnDismissed; | |
| 34 | |
| 35 private RadioGroup mRadioGroup; | |
| 36 private String mSelectedKeyword; | |
| 37 | |
| 38 /** | |
| 39 * Construct and show the dialog. Will be asynchronous if the TemplateUrlSe rvice has not yet | |
| 40 * been loaded. | |
| 41 */ | |
| 42 public static void create( | |
|
Ted C
2017/04/26 20:21:52
maybe this should be called show?
gone
2017/04/26 21:45:15
Done.
| |
| 43 final Context context, final int dialogType, @Nullable final Runnabl e onDismissed) { | |
|
Ted C
2017/04/26 20:21:52
Should/can dialogType have an associated IntDef?
gone
2017/04/26 21:45:15
Seems like it'd be fine to move it to always be ca
| |
| 44 assert LibraryLoader.isInitialized(); | |
| 45 | |
| 46 // Load up the search engines. | |
| 47 final TemplateUrlService instance = TemplateUrlService.getInstance(); | |
| 48 instance.registerLoadListener(new TemplateUrlService.LoadListener() { | |
| 49 @Override | |
| 50 public void onTemplateUrlServiceLoaded() { | |
| 51 instance.unregisterLoadListener(this); | |
| 52 new DefaultSearchEnginePromoDialog(context, dialogType, onDismis sed).show(); | |
| 53 } | |
| 54 }); | |
| 55 instance.load(); | |
| 56 } | |
| 57 | |
| 58 private DefaultSearchEnginePromoDialog( | |
| 59 Context context, int dialogType, @Nullable Runnable onDismissed) { | |
| 60 super(context); | |
| 61 mDialogType = dialogType; | |
| 62 mOnDismissed = onDismissed; | |
| 63 setOnDismissListener(this); | |
| 64 | |
| 65 // No one should be able to bypass this dialog by clicking outside or by hitting back. | |
| 66 setCancelable(false); | |
| 67 setCanceledOnTouchOutside(false); | |
| 68 } | |
| 69 | |
| 70 @Override | |
| 71 protected DialogParams getDialogParams() { | |
| 72 PromoDialog.DialogParams params = new PromoDialog.DialogParams(); | |
| 73 params.headerStringResource = R.string.search_engine_dialog_title; | |
| 74 params.footerStringResource = R.string.search_engine_dialog_footer; | |
| 75 params.primaryButtonStringResource = R.string.ok; | |
| 76 return params; | |
| 77 } | |
| 78 | |
| 79 @Override | |
| 80 protected void onCreate(Bundle savedInstanceState) { | |
| 81 super.onCreate(savedInstanceState); | |
| 82 assert LibraryLoader.isInitialized(); | |
|
Ted C
2017/04/26 20:21:52
Since this happens in the one place you create it
gone
2017/04/26 21:45:15
Done.
| |
| 83 | |
| 84 // Set up the general UI. | |
| 85 InfoBarControlLayout controls = addControlLayout(); | |
| 86 updateButtonState(); | |
| 87 | |
| 88 // Load up the search engines. | |
| 89 TemplateUrlService instance = TemplateUrlService.getInstance(); | |
| 90 assert instance.isLoaded(); | |
| 91 List<TemplateUrl> engines = null; | |
| 92 if (mDialogType == LocaleManager.SEARCH_ENGINE_PROMO_SHOW_EXISTING) { | |
| 93 engines = instance.getSearchEngines(); | |
| 94 } else { | |
| 95 // TODO(dfalcantara): Handle the new user case. | |
| 96 assert false; | |
| 97 } | |
| 98 | |
| 99 List<CharSequence> engineNames = new ArrayList<>(); | |
| 100 List<String> engineKeywords = new ArrayList<>(); | |
| 101 shuffleEngines(engines, engineNames, engineKeywords); | |
| 102 | |
| 103 // Add the search engines to the dialog. | |
| 104 mRadioGroup = controls.addRadioButtons( | |
| 105 engineNames, engineKeywords, InfoBarControlLayout.INVALID_INDEX) ; | |
| 106 mRadioGroup.setOnCheckedChangeListener(this); | |
| 107 } | |
| 108 | |
| 109 @Override | |
| 110 public void onCheckedChanged(RadioGroup group, int checkedId) { | |
| 111 mSelectedKeyword = null; | |
| 112 | |
| 113 // Run through the RadioGroup to figure out which one was checked. | |
| 114 for (int i = 0; i < group.getChildCount(); i++) { | |
| 115 View child = group.getChildAt(i); | |
| 116 assert child instanceof RadioButton; | |
| 117 | |
| 118 RadioButton button = (RadioButton) child; | |
| 119 if (button.isChecked()) { | |
| 120 assert mSelectedKeyword == null; | |
| 121 mSelectedKeyword = (String) button.getTag(); | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 updateButtonState(); | |
| 126 } | |
| 127 | |
| 128 @Override | |
| 129 public void onClick(View view) { | |
| 130 if (view.getId() == R.id.button_primary) { | |
| 131 if (mSelectedKeyword == null) { | |
| 132 updateButtonState(); | |
| 133 return; | |
| 134 } | |
| 135 | |
| 136 dismiss(); | |
| 137 } else { | |
| 138 assert false : "Unhandled click."; | |
| 139 } | |
| 140 | |
| 141 // Don't propagate the click to the parent to prevent circumventing the dialog. | |
| 142 } | |
| 143 | |
| 144 @Override | |
| 145 public void onDismiss(DialogInterface dialog) { | |
| 146 if (mSelectedKeyword == null) { | |
| 147 // This shouldn't happen, but in case it does, finish the Activity s o that the user has | |
| 148 // to respond to the dialog next time. | |
| 149 if (getOwnerActivity() != null) getOwnerActivity().finish(); | |
|
Ted C
2017/04/26 20:21:52
should this be finish and remove task?
gone
2017/04/26 21:45:15
I'd argue for a regular finish() so that the activ
| |
| 150 } else { | |
| 151 TemplateUrlService.getInstance().setSearchEngine(mSelectedKeyword.to String()); | |
| 152 if (mOnDismissed != null) mOnDismissed.run(); | |
| 153 // TODO(dfalcantara): Prevent the dialog from appearing again. | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 private void updateButtonState() { | |
| 158 findViewById(R.id.button_primary).setEnabled(mSelectedKeyword != null); | |
| 159 } | |
| 160 | |
| 161 private void shuffleEngines( | |
| 162 List<TemplateUrl> engines, List<CharSequence> names, List<String> ke ywords) { | |
| 163 ArrayList<Integer> indices = new ArrayList<>(); | |
|
Ted C
2017/04/26 20:21:52
Could we use:
https://developer.android.com/refere
gone
2017/04/26 21:45:15
Works for me.
| |
| 164 for (int i = 0; i < engines.size(); i++) indices.add(i); | |
| 165 | |
| 166 Random generator = new Random(); | |
| 167 for (int i = 0; i < indices.size(); i++) { | |
| 168 int remaining = indices.size() - i; | |
| 169 int shuffleIndex = i + generator.nextInt(remaining); | |
| 170 | |
| 171 if (shuffleIndex != i) { | |
| 172 int temp = indices.get(i); | |
| 173 indices.set(i, indices.get(shuffleIndex)); | |
| 174 indices.set(shuffleIndex, temp); | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 for (Integer index : indices) { | |
| 179 TemplateUrl engine = engines.get(index); | |
| 180 names.add(engine.getShortName()); | |
| 181 keywords.add(engine.getKeyword()); | |
| 182 } | |
| 183 } | |
| 184 } | |
| OLD | NEW |