Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java

Issue 1739523002: WebUsb Android chooser UI (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser; 5 package org.chromium.chrome.browser;
6 6
7 import android.Manifest; 7 import android.Manifest;
8 import android.content.Context; 8 import android.content.Context;
9 import android.content.Intent; 9 import android.content.Intent;
10 import android.content.pm.PackageManager; 10 import android.content.pm.PackageManager;
11 import android.graphics.Color;
12 import android.text.SpannableString; 11 import android.text.SpannableString;
13 import android.text.TextPaint;
14 import android.text.TextUtils; 12 import android.text.TextUtils;
15 import android.text.style.ClickableSpan;
16 import android.view.View; 13 import android.view.View;
17 14
18 import org.chromium.base.VisibleForTesting; 15 import org.chromium.base.VisibleForTesting;
19 import org.chromium.base.annotations.CalledByNative; 16 import org.chromium.base.annotations.CalledByNative;
20 import org.chromium.chrome.R; 17 import org.chromium.chrome.R;
21 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer; 18 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer;
22 import org.chromium.chrome.browser.profiles.Profile; 19 import org.chromium.chrome.browser.profiles.Profile;
23 import org.chromium.ui.base.WindowAndroid; 20 import org.chromium.ui.base.WindowAndroid;
21 import org.chromium.ui.text.NoUnderlineClickableSpan;
24 import org.chromium.ui.text.SpanApplier; 22 import org.chromium.ui.text.SpanApplier;
25 import org.chromium.ui.text.SpanApplier.SpanInfo; 23 import org.chromium.ui.text.SpanApplier.SpanInfo;
26 24
27 import java.util.ArrayList;
28 import java.util.List;
29
30 /** 25 /**
31 * A dialog for picking available Bluetooth devices. This dialog is shown when a website requests to 26 * A dialog for picking available Bluetooth devices. This dialog is shown when a website requests to
32 * pair with a certain class of Bluetooth devices (e.g. through a bluetooth.requ estDevice Javascript 27 * pair with a certain class of Bluetooth devices (e.g. through a bluetooth.requ estDevice Javascript
33 * call). 28 * call).
34 */ 29 */
35 public class BluetoothChooserDialog 30 public class BluetoothChooserDialog
36 implements ItemChooserDialog.ItemSelectedCallback, WindowAndroid.Permiss ionCallback { 31 implements ItemChooserDialog.ItemSelectedCallback, WindowAndroid.Permiss ionCallback {
37 // These constants match BluetoothChooserAndroid::ShowDiscoveryState, and ar e used in 32 // These constants match BluetoothChooserAndroid::ShowDiscoveryState, and ar e used in
38 // notifyDiscoveryState(). 33 // notifyDiscoveryState().
39 static final int DISCOVERY_FAILED_TO_START = 0; 34 static final int DISCOVERY_FAILED_TO_START = 0;
(...skipping 29 matching lines...) Expand all
69 private enum LinkType { 64 private enum LinkType {
70 EXPLAIN_BLUETOOTH, 65 EXPLAIN_BLUETOOTH,
71 ADAPTER_OFF, 66 ADAPTER_OFF,
72 ADAPTER_OFF_HELP, 67 ADAPTER_OFF_HELP,
73 REQUEST_LOCATION_PERMISSION, 68 REQUEST_LOCATION_PERMISSION,
74 NEED_LOCATION_PERMISSION_HELP, 69 NEED_LOCATION_PERMISSION_HELP,
75 RESTART_SEARCH, 70 RESTART_SEARCH,
76 } 71 }
77 72
78 /** 73 /**
79 * Creates the BluetoothChooserDialog and displays it (and starts waiting fo r data). 74 * Creates the BluetoothChooserDialog.
80 *
81 * @param context Context which is used for launching a dialog.
82 */ 75 */
83 @VisibleForTesting 76 @VisibleForTesting
84 BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int secur ityLevel, 77 BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int secur ityLevel,
85 long nativeBluetoothChooserDialogPtr) { 78 long nativeBluetoothChooserDialogPtr) {
86 mWindowAndroid = windowAndroid; 79 mWindowAndroid = windowAndroid;
87 mContext = windowAndroid.getActivity().get(); 80 mContext = windowAndroid.getActivity().get();
88 assert mContext != null; 81 assert mContext != null;
89 mOrigin = origin; 82 mOrigin = origin;
90 mSecurityLevel = securityLevel; 83 mSecurityLevel = securityLevel;
91 mNativeBluetoothChooserDialogPtr = nativeBluetoothChooserDialogPtr; 84 mNativeBluetoothChooserDialogPtr = nativeBluetoothChooserDialogPtr;
(...skipping 11 matching lines...) Expand all
103 origin, mContext.getResources(), profile, mSecurityLevel, false, true, true); 96 origin, mContext.getResources(), profile, mSecurityLevel, false, true, true);
104 // Construct a full string and replace the origin text with emphasized v ersion. 97 // Construct a full string and replace the origin text with emphasized v ersion.
105 SpannableString title = 98 SpannableString title =
106 new SpannableString(mContext.getString(R.string.bluetooth_dialog _title, mOrigin)); 99 new SpannableString(mContext.getString(R.string.bluetooth_dialog _title, mOrigin));
107 int start = title.toString().indexOf(mOrigin); 100 int start = title.toString().indexOf(mOrigin);
108 TextUtils.copySpansFrom(origin, 0, origin.length(), Object.class, title, start); 101 TextUtils.copySpansFrom(origin, 0, origin.length(), Object.class, title, start);
109 102
110 String message = mContext.getString(R.string.bluetooth_not_found); 103 String message = mContext.getString(R.string.bluetooth_not_found);
111 SpannableString noneFound = SpanApplier.applySpans( 104 SpannableString noneFound = SpanApplier.applySpans(
112 message, new SpanInfo("<link>", "</link>", 105 message, new SpanInfo("<link>", "</link>",
113 new NoUnderlineClickableSpan(LinkType.RESTART_SEARCH, mC ontext))); 106 new BluetoothClickableSpan(LinkType.RESTART_SEARCH, mCon text)));
114 107
115 SpannableString searching = SpanApplier.applySpans( 108 SpannableString searching = SpanApplier.applySpans(
116 mContext.getString(R.string.bluetooth_searching), 109 mContext.getString(R.string.bluetooth_searching),
117 new SpanInfo("<link>", "</link>", 110 new SpanInfo("<link>", "</link>",
newt (away) 2016/03/17 01:53:20 nit: The indentation was correct to begin with (be
juncai 2016/03/17 18:21:35 Done.
118 new NoUnderlineClickableSpan(LinkType.EXPLAIN_BLUETOOTH, mContext))); 111 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUE TOOTH, mContext)));
119 112
120 String positiveButton = mContext.getString(R.string.bluetooth_confirm_bu tton); 113 String positiveButton = mContext.getString(R.string.bluetooth_confirm_bu tton);
121 114
122 SpannableString statusActive = SpanApplier.applySpans(
123 mContext.getString(R.string.bluetooth_not_seeing_it),
124 new SpanInfo("<link>", "</link>",
125 new NoUnderlineClickableSpan(LinkType.EXPLAIN_BLUETOOTH, mContext)));
126
127 SpannableString statusIdleNoneFound = SpanApplier.applySpans( 115 SpannableString statusIdleNoneFound = SpanApplier.applySpans(
128 mContext.getString(R.string.bluetooth_not_seeing_it_idle_none_fo und), 116 mContext.getString(R.string.bluetooth_not_seeing_it_idle_none_fo und),
129 new SpanInfo("<link>", "</link>", 117 new SpanInfo("<link>", "</link>",
130 new NoUnderlineClickableSpan(LinkType.EXPLAIN_BLUETOOTH, mContext))); 118 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUE TOOTH, mContext)));
131 119
132 SpannableString statusIdleSomeFound = SpanApplier.applySpans( 120 SpannableString statusIdleSomeFound = SpanApplier.applySpans(
133 mContext.getString(R.string.bluetooth_not_seeing_it_idle_some_fo und), 121 mContext.getString(R.string.bluetooth_not_seeing_it_idle_some_fo und),
134 new SpanInfo("<link1>", "</link1>", 122 new SpanInfo("<link1>", "</link1>",
135 new NoUnderlineClickableSpan(LinkType.EXPLAIN_BLUETOOTH, mContext)), 123 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUETOOTH, m Context)),
136 new SpanInfo("<link2>", "</link2>", 124 new SpanInfo("<link2>", "</link2>",
137 new NoUnderlineClickableSpan(LinkType.RESTART_SEARCH, mC ontext))); 125 new BluetoothClickableSpan(LinkType.RESTART_SEARCH, mCon text)));
138 126
139 ItemChooserDialog.ItemChooserLabels labels = 127 ItemChooserDialog.ItemChooserLabels labels =
140 new ItemChooserDialog.ItemChooserLabels(title, searching, noneFo und, statusActive, 128 new ItemChooserDialog.ItemChooserLabels(title, searching, noneFo und,
141 statusIdleNoneFound, statusIdleSomeFound, positiveButton ); 129 statusIdleNoneFound, statusIdleSomeFound, positiveButton );
142 mItemChooserDialog = new ItemChooserDialog(mContext, this, labels); 130 mItemChooserDialog = new ItemChooserDialog(mContext, this, labels);
143 } 131 }
144 132
145 @Override 133 @Override
146 public void onItemSelected(String id) { 134 public void onItemSelected(String id) {
147 if (mNativeBluetoothChooserDialogPtr != 0) { 135 if (mNativeBluetoothChooserDialogPtr != 0) {
148 if (id.isEmpty()) { 136 if (id.isEmpty()) {
149 nativeOnDialogFinished( 137 nativeOnDialogFinished(
150 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_CANCEL LED, ""); 138 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_CANCEL LED, "");
(...skipping 30 matching lines...) Expand all
181 if (mNativeBluetoothChooserDialogPtr != 0) { 169 if (mNativeBluetoothChooserDialogPtr != 0) {
182 nativeOnDialogFinished( 170 nativeOnDialogFinished(
183 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_DENIED _PERMISSION, ""); 171 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_DENIED _PERMISSION, "");
184 return; 172 return;
185 } 173 }
186 } 174 }
187 175
188 SpannableString needLocationMessage = SpanApplier.applySpans( 176 SpannableString needLocationMessage = SpanApplier.applySpans(
189 mContext.getString(R.string.bluetooth_need_location_permission), 177 mContext.getString(R.string.bluetooth_need_location_permission),
190 new SpanInfo("<link>", "</link>", 178 new SpanInfo("<link>", "</link>",
191 new NoUnderlineClickableSpan( 179 new BluetoothClickableSpan(
192 LinkType.REQUEST_LOCATION_PERMISSION, mCont ext))); 180 LinkType.REQUEST_LOCATION_PERMISSION, mCont ext)));
193 181
194 SpannableString needLocationStatus = SpanApplier.applySpans( 182 SpannableString needLocationStatus = SpanApplier.applySpans(
195 mContext.getString(R.string.bluetooth_need_location_permission_h elp), 183 mContext.getString(R.string.bluetooth_need_location_permission_h elp),
196 new SpanInfo("<link>", "</link>", 184 new SpanInfo("<link>", "</link>",
197 new NoUnderlineClickableSpan( 185 new BluetoothClickableSpan(
198 LinkType.NEED_LOCATION_PERMISSION_HELP, mCo ntext))); 186 LinkType.NEED_LOCATION_PERMISSION_HELP, mCo ntext)));
199 187
200 mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus ); 188 mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus );
201 } 189 }
202 190
203 /** 191 private class BluetoothClickableSpan extends NoUnderlineClickableSpan {
204 * A helper class to show a clickable link with underlines turned off.
205 */
206 private class NoUnderlineClickableSpan extends ClickableSpan {
207 // The type of link this span represents. 192 // The type of link this span represents.
208 private LinkType mLinkType; 193 private LinkType mLinkType;
209 194
210 private Context mContext; 195 private Context mContext;
211 196
212 NoUnderlineClickableSpan(LinkType linkType, Context context) { 197 BluetoothClickableSpan(LinkType linkType, Context context) {
213 mLinkType = linkType; 198 mLinkType = linkType;
214 mContext = context; 199 mContext = context;
215 } 200 }
216 201
217 @Override 202 @Override
218 public void onClick(View view) { 203 public void onClick(View view) {
219 if (mNativeBluetoothChooserDialogPtr == 0) { 204 if (mNativeBluetoothChooserDialogPtr == 0) {
220 return; 205 return;
221 } 206 }
222 207
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); 242 nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
258 break; 243 break;
259 } 244 }
260 default: 245 default:
261 assert false; 246 assert false;
262 } 247 }
263 248
264 // Get rid of the highlight background on selection. 249 // Get rid of the highlight background on selection.
265 view.invalidate(); 250 view.invalidate();
266 } 251 }
267
268 @Override
269 public void updateDrawState(TextPaint textPaint) {
270 super.updateDrawState(textPaint);
271 textPaint.bgColor = Color.TRANSPARENT;
272 textPaint.setUnderlineText(false);
273 }
274 } 252 }
275 253
276 @CalledByNative 254 @CalledByNative
277 private static BluetoothChooserDialog create(WindowAndroid windowAndroid, St ring origin, 255 private static BluetoothChooserDialog create(WindowAndroid windowAndroid, St ring origin,
278 int securityLevel, long nativeBluetoothChooserDialogPtr) { 256 int securityLevel, long nativeBluetoothChooserDialogPtr) {
279 if (!windowAndroid.hasPermission(Manifest.permission.ACCESS_COARSE_LOCAT ION) 257 if (!windowAndroid.hasPermission(Manifest.permission.ACCESS_COARSE_LOCAT ION)
280 && !windowAndroid.hasPermission(Manifest.permission.ACCESS_FINE_ LOCATION) 258 && !windowAndroid.hasPermission(Manifest.permission.ACCESS_FINE_ LOCATION)
281 && !windowAndroid.canRequestPermission( 259 && !windowAndroid.canRequestPermission(
282 Manifest.permission.ACCESS_COARSE_LOCATION)) { 260 Manifest.permission.ACCESS_COARSE_LOCATION)) {
283 // If we can't even ask for enough permission to scan for Bluetooth devices, don't open 261 // If we can't even ask for enough permission to scan for Bluetooth devices, don't open
284 // the dialog. 262 // the dialog.
285 return null; 263 return null;
286 } 264 }
287 BluetoothChooserDialog dialog = new BluetoothChooserDialog( 265 BluetoothChooserDialog dialog = new BluetoothChooserDialog(
288 windowAndroid, origin, securityLevel, nativeBluetoothChooserDial ogPtr); 266 windowAndroid, origin, securityLevel, nativeBluetoothChooserDial ogPtr);
289 dialog.show(); 267 dialog.show();
290 return dialog; 268 return dialog;
291 } 269 }
292 270
293 @VisibleForTesting 271 @VisibleForTesting
294 @CalledByNative 272 @CalledByNative
295 void addDevice(String deviceId, String deviceName) { 273 void addDevice(String deviceId, String deviceName) {
296 List<ItemChooserDialog.ItemChooserRow> devices = 274 mItemChooserDialog.addItemToList(
297 new ArrayList<ItemChooserDialog.ItemChooserRow>(); 275 new ItemChooserDialog.ItemChooserRow(deviceId, deviceName));
298 devices.add(new ItemChooserDialog.ItemChooserRow(deviceId, deviceName));
299 mItemChooserDialog.addItemsToList(devices);
300 } 276 }
301 277
302 @VisibleForTesting 278 @VisibleForTesting
303 @CalledByNative 279 @CalledByNative
304 void closeDialog() { 280 void closeDialog() {
305 mNativeBluetoothChooserDialogPtr = 0; 281 mNativeBluetoothChooserDialogPtr = 0;
306 mItemChooserDialog.dismiss(); 282 mItemChooserDialog.dismiss();
307 } 283 }
308 284
309 @VisibleForTesting 285 @VisibleForTesting
310 @CalledByNative 286 @CalledByNative
311 void removeDevice(String deviceId) { 287 void removeDevice(String deviceId) {
312 mItemChooserDialog.setEnabled(deviceId, false); 288 mItemChooserDialog.setEnabled(deviceId, false);
313 } 289 }
314 290
315 @VisibleForTesting 291 @VisibleForTesting
316 @CalledByNative 292 @CalledByNative
317 void notifyAdapterTurnedOff() { 293 void notifyAdapterTurnedOff() {
318 SpannableString adapterOffMessage = SpanApplier.applySpans( 294 SpannableString adapterOffMessage = SpanApplier.applySpans(
319 mContext.getString(R.string.bluetooth_adapter_off), 295 mContext.getString(R.string.bluetooth_adapter_off),
320 new SpanInfo("<link>", "</link>", 296 new SpanInfo("<link>", "</link>",
321 new NoUnderlineClickableSpan(LinkType.ADAPTER_OFF, mCont ext))); 297 new BluetoothClickableSpan(LinkType.ADAPTER_OFF, mContex t)));
322 SpannableString adapterOffStatus = SpanApplier.applySpans( 298 SpannableString adapterOffStatus = SpanApplier.applySpans(
323 mContext.getString(R.string.bluetooth_adapter_off_help), 299 mContext.getString(R.string.bluetooth_adapter_off_help),
324 new SpanInfo("<link>", "</link>", 300 new SpanInfo("<link>", "</link>",
325 new NoUnderlineClickableSpan(LinkType.ADAPTER_OFF_HELP, mContext))); 301 new BluetoothClickableSpan(LinkType.ADAPTER_OFF_HELP, mC ontext)));
326 302
327 mItemChooserDialog.setErrorState(adapterOffMessage, adapterOffStatus); 303 mItemChooserDialog.setErrorState(adapterOffMessage, adapterOffStatus);
328 } 304 }
329 305
330 @CalledByNative 306 @CalledByNative
331 private void notifyAdapterTurnedOn() { 307 private void notifyAdapterTurnedOn() {
332 mItemChooserDialog.clear(); 308 mItemChooserDialog.clear();
333 if (mNativeBluetoothChooserDialogPtr != 0) { 309 if (mNativeBluetoothChooserDialogPtr != 0) {
334 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); 310 nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
335 } 311 }
(...skipping 26 matching lines...) Expand all
362 @VisibleForTesting 338 @VisibleForTesting
363 native void nativeRestartSearch(long nativeBluetoothChooserAndroid); 339 native void nativeRestartSearch(long nativeBluetoothChooserAndroid);
364 // Help links. 340 // Help links.
365 @VisibleForTesting 341 @VisibleForTesting
366 native void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndro id); 342 native void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndro id);
367 @VisibleForTesting 343 @VisibleForTesting
368 native void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAnd roid); 344 native void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAnd roid);
369 @VisibleForTesting 345 @VisibleForTesting
370 native void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooser Android); 346 native void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooser Android);
371 } 347 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698