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

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: Sync 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
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
12 import android.text.SpannableString; 14 import android.text.SpannableString;
13 import android.text.TextUtils; 15 import android.text.TextUtils;
14 import android.view.View; 16 import android.view.View;
15 17
16 import org.chromium.base.VisibleForTesting; 18 import org.chromium.base.VisibleForTesting;
17 import org.chromium.base.annotations.CalledByNative; 19 import org.chromium.base.annotations.CalledByNative;
18 import org.chromium.chrome.R; 20 import org.chromium.chrome.R;
19 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer; 21 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer;
20 import org.chromium.chrome.browser.profiles.Profile; 22 import org.chromium.chrome.browser.profiles.Profile;
21 import org.chromium.components.location.LocationUtils; 23 import org.chromium.components.location.LocationUtils;
22 import org.chromium.ui.base.WindowAndroid; 24 import org.chromium.ui.base.WindowAndroid;
23 import org.chromium.ui.text.NoUnderlineClickableSpan; 25 import org.chromium.ui.text.NoUnderlineClickableSpan;
24 import org.chromium.ui.text.SpanApplier; 26 import org.chromium.ui.text.SpanApplier;
25 import org.chromium.ui.text.SpanApplier.SpanInfo; 27 import org.chromium.ui.text.SpanApplier.SpanInfo;
26 28
27 /** 29 /**
28 * A dialog for picking available Bluetooth devices. This dialog is shown when a website requests to 30 * A dialog for picking available Bluetooth devices. This dialog is shown when a website requests to
29 * pair with a certain class of Bluetooth devices (e.g. through a bluetooth.requ estDevice Javascript 31 * pair with a certain class of Bluetooth devices (e.g. through a bluetooth.requ estDevice Javascript
30 * call). 32 * call).
33 *
34 * The dialog is shown by create() or show(), and always runs finishDialog() as it's closing.
31 */ 35 */
32 public class BluetoothChooserDialog 36 public class BluetoothChooserDialog
33 implements ItemChooserDialog.ItemSelectedCallback, WindowAndroid.Permiss ionCallback { 37 implements ItemChooserDialog.ItemSelectedCallback, WindowAndroid.Permiss ionCallback {
34 // These constants match BluetoothChooserAndroid::ShowDiscoveryState, and ar e used in 38 // These constants match BluetoothChooserAndroid::ShowDiscoveryState, and ar e used in
35 // notifyDiscoveryState(). 39 // notifyDiscoveryState().
36 static final int DISCOVERY_FAILED_TO_START = 0; 40 static final int DISCOVERY_FAILED_TO_START = 0;
37 static final int DISCOVERING = 1; 41 static final int DISCOVERING = 1;
38 static final int DISCOVERY_IDLE = 2; 42 static final int DISCOVERY_IDLE = 2;
39 43
40 // Values passed to nativeOnDialogFinished:eventType, and only used in the n ative function. 44 // Values passed to nativeOnDialogFinished:eventType, and only used in the n ative function.
(...skipping 20 matching lines...) Expand all
61 65
62 // A pointer back to the native part of the implementation for this dialog. 66 // A pointer back to the native part of the implementation for this dialog.
63 long mNativeBluetoothChooserDialogPtr; 67 long mNativeBluetoothChooserDialogPtr;
64 68
65 // The type of link that is shown within the dialog. 69 // The type of link that is shown within the dialog.
66 private enum LinkType { 70 private enum LinkType {
67 EXPLAIN_BLUETOOTH, 71 EXPLAIN_BLUETOOTH,
68 ADAPTER_OFF, 72 ADAPTER_OFF,
69 ADAPTER_OFF_HELP, 73 ADAPTER_OFF_HELP,
70 REQUEST_LOCATION_PERMISSION, 74 REQUEST_LOCATION_PERMISSION,
75 REQUEST_LOCATION_SERVICES,
71 NEED_LOCATION_PERMISSION_HELP, 76 NEED_LOCATION_PERMISSION_HELP,
72 RESTART_SEARCH, 77 RESTART_SEARCH,
73 } 78 }
74 79
75 /** 80 /**
76 * Creates the BluetoothChooserDialog. 81 * Creates the BluetoothChooserDialog.
77 */ 82 */
78 @VisibleForTesting 83 @VisibleForTesting
79 BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int secur ityLevel, 84 BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int secur ityLevel,
80 long nativeBluetoothChooserDialogPtr) { 85 long nativeBluetoothChooserDialogPtr) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 mActivity.getString(R.string.bluetooth_not_seeing_it_idle_some_f ound), 128 mActivity.getString(R.string.bluetooth_not_seeing_it_idle_some_f ound),
124 new SpanInfo("<link1>", "</link1>", 129 new SpanInfo("<link1>", "</link1>",
125 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUETOOTH, m Activity)), 130 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUETOOTH, m Activity)),
126 new SpanInfo("<link2>", "</link2>", 131 new SpanInfo("<link2>", "</link2>",
127 new BluetoothClickableSpan(LinkType.RESTART_SEARCH, mAct ivity))); 132 new BluetoothClickableSpan(LinkType.RESTART_SEARCH, mAct ivity)));
128 133
129 ItemChooserDialog.ItemChooserLabels labels = 134 ItemChooserDialog.ItemChooserLabels labels =
130 new ItemChooserDialog.ItemChooserLabels(title, searching, noneFo und, 135 new ItemChooserDialog.ItemChooserLabels(title, searching, noneFo und,
131 statusIdleNoneFound, statusIdleSomeFound, positiveButton ); 136 statusIdleNoneFound, statusIdleSomeFound, positiveButton );
132 mItemChooserDialog = new ItemChooserDialog(mActivity, this, labels); 137 mItemChooserDialog = new ItemChooserDialog(mActivity, this, labels);
138
139 mActivity.registerReceiver(mLocationModeBroadcastReceiver,
140 new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
141 }
142
143 // Called to report the dialog's results back to native code.
144 private void finishDialog(int resultCode, String id) {
145 mActivity.unregisterReceiver(mLocationModeBroadcastReceiver);
146 if (mNativeBluetoothChooserDialogPtr != 0) {
147 nativeOnDialogFinished(mNativeBluetoothChooserDialogPtr, resultCode, id);
148 }
133 } 149 }
134 150
135 @Override 151 @Override
136 public void onItemSelected(String id) { 152 public void onItemSelected(String id) {
137 if (mNativeBluetoothChooserDialogPtr != 0) { 153 if (id.isEmpty()) {
138 if (id.isEmpty()) { 154 finishDialog(DIALOG_FINISHED_CANCELLED, "");
139 nativeOnDialogFinished( 155 } else {
140 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_CANCEL LED, ""); 156 finishDialog(DIALOG_FINISHED_SELECTED, id);
141 } else {
142 nativeOnDialogFinished(
143 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_SELECT ED, id);
144 }
145 } 157 }
146 } 158 }
147 159
148 @Override 160 @Override
149 public void onRequestPermissionsResult(String[] permissions, int[] grantResu lts) { 161 public void onRequestPermissionsResult(String[] permissions, int[] grantResu lts) {
150 for (int i = 0; i < grantResults.length; i++) { 162 for (int i = 0; i < permissions.length; i++) {
151 if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION )) { 163 if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION )) {
152 if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { 164 if (checkLocationServicesAndPermission()) {
153 mItemChooserDialog.clear(); 165 mItemChooserDialog.clear();
154 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); 166 nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
155 } else {
156 checkLocationPermission();
157 } 167 }
158 return; 168 return;
159 } 169 }
160 } 170 }
161 // If the location permission is not present, leave the currently-shown message in place. 171 // If the location permission is not present, leave the currently-shown message in place.
162 } 172 }
163 173
164 private void checkLocationPermission() { 174 @VisibleForTesting
165 if (LocationUtils.getInstance().hasAndroidLocationPermission(mActivity)) { 175 final BroadcastReceiver mLocationModeBroadcastReceiver = new BroadcastReceiv er() {
166 return; 176 @Override
177 public void onReceive(Context context, Intent intent) {
178 if (LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction())) {
179 if (checkLocationServicesAndPermission()) {
180 mItemChooserDialog.clear();
181 nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
182 }
183 }
184 }
185 };
186
187 // Returns true if Location Services is on and Chrome has permission to see the user's location.
188 private boolean checkLocationServicesAndPermission() {
189 final boolean havePermission =
190 LocationUtils.getInstance().hasAndroidLocationPermission(mActivi ty);
191 final boolean locationServicesOn =
192 LocationUtils.getInstance().isSystemLocationSettingEnabled(mActi vity);
193
194 if (!havePermission
195 && !mWindowAndroid.canRequestPermission(
196 Manifest.permission.ACCESS_COARSE_LOCATION)) {
197 // Immediately close the dialog because the user has asked Chrome no t to request the
198 // location permission.
199 finishDialog(DIALOG_FINISHED_DENIED_PERMISSION, "");
200 return false;
167 } 201 }
168 202
169 if (!mWindowAndroid.canRequestPermission(Manifest.permission.ACCESS_COAR SE_LOCATION)) { 203 // Compute the message to show the user.
170 if (mNativeBluetoothChooserDialogPtr != 0) { 204 final SpanInfo permissionSpan = new SpanInfo("<permission_link>", "</per mission_link>",
171 nativeOnDialogFinished( 205 new BluetoothClickableSpan(LinkType.REQUEST_LOCATION_PERMISSION, mActivity));
172 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_DENIED _PERMISSION, ""); 206 final SpanInfo servicesSpan = new SpanInfo("<services_link>", "</service s_link>",
173 return; 207 new BluetoothClickableSpan(LinkType.REQUEST_LOCATION_SERVICES, m Activity));
208 final SpannableString needLocationMessage;
209 if (havePermission) {
210 if (locationServicesOn) {
211 // We don't need to request anything.
212 return true;
213 } else {
214 needLocationMessage = SpanApplier.applySpans(
215 mActivity.getString(R.string.bluetooth_need_location_ser vices_on),
216 servicesSpan);
217 }
218 } else {
219 if (locationServicesOn) {
220 needLocationMessage = SpanApplier.applySpans(
221 mActivity.getString(R.string.bluetooth_need_location_per mission),
222 permissionSpan);
223 } else {
224 needLocationMessage = SpanApplier.applySpans(
225 mActivity.getString(
226 R.string.bluetooth_need_location_permission_and_ services_on),
227 permissionSpan, servicesSpan);
174 } 228 }
175 } 229 }
176 230
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( 231 SpannableString needLocationStatus = SpanApplier.applySpans(
184 mActivity.getString(R.string.bluetooth_need_location_permission_ help), 232 mActivity.getString(R.string.bluetooth_need_location_permission_ help),
185 new SpanInfo("<link>", "</link>", 233 new SpanInfo("<link>", "</link>",
186 new BluetoothClickableSpan( 234 new BluetoothClickableSpan(
187 LinkType.NEED_LOCATION_PERMISSION_HELP, mAc tivity))); 235 LinkType.NEED_LOCATION_PERMISSION_HELP, mAc tivity)));
188 236
189 mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus ); 237 mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus );
238 return false;
190 } 239 }
191 240
192 private class BluetoothClickableSpan extends NoUnderlineClickableSpan { 241 private class BluetoothClickableSpan extends NoUnderlineClickableSpan {
193 // The type of link this span represents. 242 // The type of link this span represents.
194 private LinkType mLinkType; 243 private LinkType mLinkType;
195 244
196 private Context mContext; 245 private Context mContext;
197 246
198 BluetoothClickableSpan(LinkType linkType, Context context) { 247 BluetoothClickableSpan(LinkType linkType, Context context) {
199 mLinkType = linkType; 248 mLinkType = linkType;
(...skipping 26 matching lines...) Expand all
226 nativeShowBluetoothAdapterOffLink(mNativeBluetoothChooserDia logPtr); 275 nativeShowBluetoothAdapterOffLink(mNativeBluetoothChooserDia logPtr);
227 closeDialog(); 276 closeDialog();
228 break; 277 break;
229 } 278 }
230 case REQUEST_LOCATION_PERMISSION: { 279 case REQUEST_LOCATION_PERMISSION: {
231 mWindowAndroid.requestPermissions( 280 mWindowAndroid.requestPermissions(
232 new String[] {Manifest.permission.ACCESS_COARSE_LOCA TION}, 281 new String[] {Manifest.permission.ACCESS_COARSE_LOCA TION},
233 BluetoothChooserDialog.this); 282 BluetoothChooserDialog.this);
234 break; 283 break;
235 } 284 }
285 case REQUEST_LOCATION_SERVICES: {
286 mContext.startActivity(
287 LocationUtils.getInstance().getSystemLocationSetting sIntent());
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
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698