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

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

Issue 2032273002: If location services are turned off, have the BT chooser prompt the user to turn them on. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: Created 4 years, 6 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.app.Activity; 8 import android.app.Activity;
9 import android.content.BroadcastReceiver;
9 import android.content.Context; 10 import android.content.Context;
10 import android.content.Intent; 11 import android.content.Intent;
11 import android.content.pm.PackageManager; 12 import android.content.IntentFilter;
13 import android.location.LocationManager;
14 import android.provider.Settings;
12 import android.text.SpannableString; 15 import android.text.SpannableString;
13 import android.text.TextUtils; 16 import android.text.TextUtils;
14 import android.view.View; 17 import android.view.View;
15 18
16 import org.chromium.base.VisibleForTesting; 19 import org.chromium.base.VisibleForTesting;
17 import org.chromium.base.annotations.CalledByNative; 20 import org.chromium.base.annotations.CalledByNative;
18 import org.chromium.chrome.R; 21 import org.chromium.chrome.R;
19 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer; 22 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer;
23 import org.chromium.chrome.browser.preferences.LocationSettings;
20 import org.chromium.chrome.browser.profiles.Profile; 24 import org.chromium.chrome.browser.profiles.Profile;
21 import org.chromium.ui.base.WindowAndroid; 25 import org.chromium.ui.base.WindowAndroid;
22 import org.chromium.ui.text.NoUnderlineClickableSpan; 26 import org.chromium.ui.text.NoUnderlineClickableSpan;
23 import org.chromium.ui.text.SpanApplier; 27 import org.chromium.ui.text.SpanApplier;
24 import org.chromium.ui.text.SpanApplier.SpanInfo; 28 import org.chromium.ui.text.SpanApplier.SpanInfo;
25 29
26 /** 30 /**
27 * A dialog for picking available Bluetooth devices. This dialog is shown when a website requests to 31 * A dialog for picking available Bluetooth devices. This dialog is shown when a website requests to
28 * pair with a certain class of Bluetooth devices (e.g. through a bluetooth.requ estDevice Javascript 32 * pair with a certain class of Bluetooth devices (e.g. through a bluetooth.requ estDevice Javascript
29 * call). 33 * call).
34 *
35 * The dialog is shown by create() or show(), and always runs finishDialog() as it's closing.
30 */ 36 */
31 public class BluetoothChooserDialog 37 public class BluetoothChooserDialog
32 implements ItemChooserDialog.ItemSelectedCallback, WindowAndroid.Permiss ionCallback { 38 implements ItemChooserDialog.ItemSelectedCallback, WindowAndroid.Permiss ionCallback {
33 // These constants match BluetoothChooserAndroid::ShowDiscoveryState, and ar e used in 39 // These constants match BluetoothChooserAndroid::ShowDiscoveryState, and ar e used in
34 // notifyDiscoveryState(). 40 // notifyDiscoveryState().
35 static final int DISCOVERY_FAILED_TO_START = 0; 41 static final int DISCOVERY_FAILED_TO_START = 0;
36 static final int DISCOVERING = 1; 42 static final int DISCOVERING = 1;
37 static final int DISCOVERY_IDLE = 2; 43 static final int DISCOVERY_IDLE = 2;
38 44
39 // Values passed to nativeOnDialogFinished:eventType, and only used in the n ative function. 45 // Values passed to nativeOnDialogFinished:eventType, and only used in the n ative function.
(...skipping 20 matching lines...) Expand all
60 66
61 // A pointer back to the native part of the implementation for this dialog. 67 // A pointer back to the native part of the implementation for this dialog.
62 long mNativeBluetoothChooserDialogPtr; 68 long mNativeBluetoothChooserDialogPtr;
63 69
64 // The type of link that is shown within the dialog. 70 // The type of link that is shown within the dialog.
65 private enum LinkType { 71 private enum LinkType {
66 EXPLAIN_BLUETOOTH, 72 EXPLAIN_BLUETOOTH,
67 ADAPTER_OFF, 73 ADAPTER_OFF,
68 ADAPTER_OFF_HELP, 74 ADAPTER_OFF_HELP,
69 REQUEST_LOCATION_PERMISSION, 75 REQUEST_LOCATION_PERMISSION,
76 REQUEST_LOCATION_SERVICES,
70 NEED_LOCATION_PERMISSION_HELP, 77 NEED_LOCATION_PERMISSION_HELP,
71 RESTART_SEARCH, 78 RESTART_SEARCH,
72 } 79 }
73 80
74 /** 81 /**
75 * Creates the BluetoothChooserDialog. 82 * Creates the BluetoothChooserDialog.
76 */ 83 */
77 @VisibleForTesting 84 @VisibleForTesting
78 BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int secur ityLevel, 85 BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int secur ityLevel,
79 long nativeBluetoothChooserDialogPtr) { 86 long nativeBluetoothChooserDialogPtr) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 mActivity.getString(R.string.bluetooth_not_seeing_it_idle_some_f ound), 129 mActivity.getString(R.string.bluetooth_not_seeing_it_idle_some_f ound),
123 new SpanInfo("<link1>", "</link1>", 130 new SpanInfo("<link1>", "</link1>",
124 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUETOOTH, m Activity)), 131 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUETOOTH, m Activity)),
125 new SpanInfo("<link2>", "</link2>", 132 new SpanInfo("<link2>", "</link2>",
126 new BluetoothClickableSpan(LinkType.RESTART_SEARCH, mAct ivity))); 133 new BluetoothClickableSpan(LinkType.RESTART_SEARCH, mAct ivity)));
127 134
128 ItemChooserDialog.ItemChooserLabels labels = 135 ItemChooserDialog.ItemChooserLabels labels =
129 new ItemChooserDialog.ItemChooserLabels(title, searching, noneFo und, 136 new ItemChooserDialog.ItemChooserLabels(title, searching, noneFo und,
130 statusIdleNoneFound, statusIdleSomeFound, positiveButton ); 137 statusIdleNoneFound, statusIdleSomeFound, positiveButton );
131 mItemChooserDialog = new ItemChooserDialog(mActivity, this, labels); 138 mItemChooserDialog = new ItemChooserDialog(mActivity, this, labels);
139
140 mActivity.registerReceiver(mLocationModeBroadcastReceiver,
141 new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
142 }
143
144 // Called to report the dialog's results back to native code.
145 private void finishDialog(int resultCode, String id) {
146 mActivity.unregisterReceiver(mLocationModeBroadcastReceiver);
147 if (mNativeBluetoothChooserDialogPtr != 0) {
148 nativeOnDialogFinished(mNativeBluetoothChooserDialogPtr, resultCode, id);
149 }
132 } 150 }
133 151
134 @Override 152 @Override
135 public void onItemSelected(String id) { 153 public void onItemSelected(String id) {
136 if (mNativeBluetoothChooserDialogPtr != 0) { 154 if (id.isEmpty()) {
137 if (id.isEmpty()) { 155 finishDialog(DIALOG_FINISHED_CANCELLED, "");
138 nativeOnDialogFinished( 156 } else {
139 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_CANCEL LED, ""); 157 finishDialog(DIALOG_FINISHED_SELECTED, id);
140 } else {
141 nativeOnDialogFinished(
142 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_SELECT ED, id);
143 }
144 } 158 }
145 } 159 }
146 160
147 @Override 161 @Override
148 public void onRequestPermissionsResult(String[] permissions, int[] grantResu lts) { 162 public void onRequestPermissionsResult(String[] permissions, int[] grantResu lts) {
149 for (int i = 0; i < grantResults.length; i++) { 163 for (int i = 0; i < permissions.length; i++) {
150 if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION )) { 164 if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION )) {
151 if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { 165 if (checkLocationServicesAndPermission()) {
152 mItemChooserDialog.clear(); 166 mItemChooserDialog.clear();
153 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); 167 nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
154 } else {
155 checkLocationPermission();
156 } 168 }
157 return; 169 return;
158 } 170 }
159 } 171 }
160 // If the location permission is not present, leave the currently-shown message in place. 172 // If the location permission is not present, leave the currently-shown message in place.
161 } 173 }
162 174
163 private void checkLocationPermission() { 175 @VisibleForTesting
164 if (mWindowAndroid.hasPermission(Manifest.permission.ACCESS_COARSE_LOCAT ION) 176 final BroadcastReceiver mLocationModeBroadcastReceiver = new BroadcastReceiv er() {
165 || mWindowAndroid.hasPermission(Manifest.permission.ACCESS_FINE_ LOCATION)) { 177 @Override
166 return; 178 public void onReceive(Context context, Intent intent) {
179 if (LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction())) {
180 if (checkLocationServicesAndPermission()) {
181 mItemChooserDialog.clear();
182 nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
183 }
184 }
185 }
186 };
187
188 // Returns true if Location Services is on and Chrome has permission to see the user's location.
189 private boolean checkLocationServicesAndPermission() {
190 final boolean havePermission =
191 mWindowAndroid.hasPermission(Manifest.permission.ACCESS_COARSE_L OCATION)
192 || mWindowAndroid.hasPermission(Manifest.permission.ACCESS_FINE_ LOCATION);
193 final boolean locationServicesOn =
194 LocationSettings.getInstance().isSystemLocationSettingEnabled();
Jeffrey Yasskin 2016/06/03 01:52:48 It's a little odd for this chooser to call into pr
Finnur 2016/06/03 02:25:04 These questions are probably more appropriate for
Ted C 2016/06/07 00:30:14 It seems to only be used in preferences right now.
195
196 if (!havePermission
197 && !mWindowAndroid.canRequestPermission(
198 Manifest.permission.ACCESS_COARSE_LOCATION)) {
199 // Immediately close the dialog because the user has asked Chrome no t to request the
200 // location permission.
201 finishDialog(DIALOG_FINISHED_DENIED_PERMISSION, "");
202 return false;
167 } 203 }
168 204
169 if (!mWindowAndroid.canRequestPermission(Manifest.permission.ACCESS_COAR SE_LOCATION)) { 205 // Compute the message to show the user.
170 if (mNativeBluetoothChooserDialogPtr != 0) { 206 final SpanInfo permissionSpan = new SpanInfo("<permission_link>", "</per mission_link>",
171 nativeOnDialogFinished( 207 new BluetoothClickableSpan(LinkType.REQUEST_LOCATION_PERMISSION, mActivity));
172 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_DENIED _PERMISSION, ""); 208 final SpanInfo servicesSpan = new SpanInfo("<services_link>", "</service s_link>",
173 return; 209 new BluetoothClickableSpan(LinkType.REQUEST_LOCATION_SERVICES, m Activity));
210 final SpannableString needLocationMessage;
211 if (havePermission) {
212 if (locationServicesOn) {
213 // We don't need to request anything.
214 return true;
215 } else {
216 needLocationMessage = SpanApplier.applySpans(
217 mActivity.getString(R.string.bluetooth_need_location_ser vices_on),
218 servicesSpan);
219 }
220 } else {
221 if (locationServicesOn) {
222 needLocationMessage = SpanApplier.applySpans(
223 mActivity.getString(R.string.bluetooth_need_location_per mission),
224 permissionSpan);
225 } else {
226 needLocationMessage = SpanApplier.applySpans(
227 mActivity.getString(
228 R.string.bluetooth_need_location_permission_and_ services_on),
229 permissionSpan, servicesSpan);
174 } 230 }
175 } 231 }
176 232
177 SpannableString needLocationMessage = SpanApplier.applySpans(
178 mActivity.getString(R.string.bluetooth_need_location_permission) ,
179 new SpanInfo("<link>", "</link>",
180 new BluetoothClickableSpan(
181 LinkType.REQUEST_LOCATION_PERMISSION, mActi vity)));
182
183 SpannableString needLocationStatus = SpanApplier.applySpans( 233 SpannableString needLocationStatus = SpanApplier.applySpans(
184 mActivity.getString(R.string.bluetooth_need_location_permission_ help), 234 mActivity.getString(R.string.bluetooth_need_location_permission_ help),
185 new SpanInfo("<link>", "</link>", 235 new SpanInfo("<link>", "</link>",
186 new BluetoothClickableSpan( 236 new BluetoothClickableSpan(
187 LinkType.NEED_LOCATION_PERMISSION_HELP, mAc tivity))); 237 LinkType.NEED_LOCATION_PERMISSION_HELP, mAc tivity)));
188 238
189 mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus ); 239 mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus );
240 return false;
190 } 241 }
191 242
192 private class BluetoothClickableSpan extends NoUnderlineClickableSpan { 243 private class BluetoothClickableSpan extends NoUnderlineClickableSpan {
193 // The type of link this span represents. 244 // The type of link this span represents.
194 private LinkType mLinkType; 245 private LinkType mLinkType;
195 246
196 private Context mContext; 247 private Context mContext;
197 248
198 BluetoothClickableSpan(LinkType linkType, Context context) { 249 BluetoothClickableSpan(LinkType linkType, Context context) {
199 mLinkType = linkType; 250 mLinkType = linkType;
(...skipping 10 matching lines...) Expand all
210 case EXPLAIN_BLUETOOTH: { 261 case EXPLAIN_BLUETOOTH: {
211 // No need to close the dialog here because 262 // No need to close the dialog here because
212 // ShowBluetoothOverviewLink will close it. 263 // ShowBluetoothOverviewLink will close it.
213 // TODO(ortuno): The BluetoothChooserDialog should dismiss 264 // TODO(ortuno): The BluetoothChooserDialog should dismiss
214 // itself when a new tab is opened or the current tab naviga tes. 265 // itself when a new tab is opened or the current tab naviga tes.
215 // https://crbug.com/588127 266 // https://crbug.com/588127
216 nativeShowBluetoothOverviewLink(mNativeBluetoothChooserDialo gPtr); 267 nativeShowBluetoothOverviewLink(mNativeBluetoothChooserDialo gPtr);
217 break; 268 break;
218 } 269 }
219 case ADAPTER_OFF: { 270 case ADAPTER_OFF: {
220 Intent intent = new Intent(); 271 mContext.startActivity(
221 intent.setAction(android.provider.Settings.ACTION_BLUETOOTH_ SETTINGS); 272 new Intent(android.provider.Settings.ACTION_BLUETOOT H_SETTINGS));
222 mContext.startActivity(intent);
223 break; 273 break;
224 } 274 }
225 case ADAPTER_OFF_HELP: { 275 case ADAPTER_OFF_HELP: {
226 nativeShowBluetoothAdapterOffLink(mNativeBluetoothChooserDia logPtr); 276 nativeShowBluetoothAdapterOffLink(mNativeBluetoothChooserDia logPtr);
227 closeDialog(); 277 closeDialog();
228 break; 278 break;
229 } 279 }
230 case REQUEST_LOCATION_PERMISSION: { 280 case REQUEST_LOCATION_PERMISSION: {
231 mWindowAndroid.requestPermissions( 281 mWindowAndroid.requestPermissions(
232 new String[] {Manifest.permission.ACCESS_COARSE_LOCA TION}, 282 new String[] {Manifest.permission.ACCESS_COARSE_LOCA TION},
233 BluetoothChooserDialog.this); 283 BluetoothChooserDialog.this);
234 break; 284 break;
235 } 285 }
286 case REQUEST_LOCATION_SERVICES: {
287 mContext.startActivity(new Intent(Settings.ACTION_LOCATION_S OURCE_SETTINGS));
288 break;
289 }
236 case NEED_LOCATION_PERMISSION_HELP: { 290 case NEED_LOCATION_PERMISSION_HELP: {
237 nativeShowNeedLocationPermissionLink(mNativeBluetoothChooser DialogPtr); 291 nativeShowNeedLocationPermissionLink(mNativeBluetoothChooser DialogPtr);
238 closeDialog(); 292 closeDialog();
239 break; 293 break;
240 } 294 }
241 case RESTART_SEARCH: { 295 case RESTART_SEARCH: {
242 mItemChooserDialog.clear(); 296 mItemChooserDialog.clear();
243 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); 297 nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
244 break; 298 break;
245 } 299 }
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 if (mNativeBluetoothChooserDialogPtr != 0) { 364 if (mNativeBluetoothChooserDialogPtr != 0) {
311 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); 365 nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
312 } 366 }
313 } 367 }
314 368
315 @VisibleForTesting 369 @VisibleForTesting
316 @CalledByNative 370 @CalledByNative
317 void notifyDiscoveryState(int discoveryState) { 371 void notifyDiscoveryState(int discoveryState) {
318 switch (discoveryState) { 372 switch (discoveryState) {
319 case DISCOVERY_FAILED_TO_START: { 373 case DISCOVERY_FAILED_TO_START: {
320 // FAILED_TO_START might be caused by a missing Location permiss ion. 374 // FAILED_TO_START might be caused by a missing Location
375 // permission or by the Location service being turned off.
321 // Check, and show a request if so. 376 // Check, and show a request if so.
322 checkLocationPermission(); 377 checkLocationServicesAndPermission();
323 break; 378 break;
324 } 379 }
325 case DISCOVERY_IDLE: { 380 case DISCOVERY_IDLE: {
326 mItemChooserDialog.setIdleState(); 381 mItemChooserDialog.setIdleState();
327 break; 382 break;
328 } 383 }
329 default: { 384 default: {
330 // TODO(jyasskin): Report the new state to the user. 385 // TODO(jyasskin): Report the new state to the user.
331 break; 386 break;
332 } 387 }
333 } 388 }
334 } 389 }
335 390
336 @VisibleForTesting 391 @VisibleForTesting
337 native void nativeOnDialogFinished( 392 native void nativeOnDialogFinished(
338 long nativeBluetoothChooserAndroid, int eventType, String deviceId); 393 long nativeBluetoothChooserAndroid, int eventType, String deviceId);
339 @VisibleForTesting 394 @VisibleForTesting
340 native void nativeRestartSearch(long nativeBluetoothChooserAndroid); 395 native void nativeRestartSearch(long nativeBluetoothChooserAndroid);
341 // Help links. 396 // Help links.
342 @VisibleForTesting 397 @VisibleForTesting
343 native void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndro id); 398 native void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndro id);
344 @VisibleForTesting 399 @VisibleForTesting
345 native void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAnd roid); 400 native void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAnd roid);
346 @VisibleForTesting 401 @VisibleForTesting
347 native void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooser Android); 402 native void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooser Android);
348 } 403 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698