| OLD | NEW |
| 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 14 matching lines...) Expand all Loading... |
| 55 // The origin for the site wanting to pair with the bluetooth devices. | 59 // The origin for the site wanting to pair with the bluetooth devices. |
| 56 String mOrigin; | 60 String mOrigin; |
| 57 | 61 |
| 58 // The security level of the connection to the site wanting to pair with the | 62 // The security level of the connection to the site wanting to pair with the |
| 59 // bluetooth devices. For valid values see SecurityStateModel::SecurityLevel
. | 63 // bluetooth devices. For valid values see SecurityStateModel::SecurityLevel
. |
| 60 int mSecurityLevel; | 64 int mSecurityLevel; |
| 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 |
| 69 @VisibleForTesting |
| 70 final BroadcastReceiver mLocationModeBroadcastReceiver = new BroadcastReceiv
er() { |
| 71 @Override |
| 72 public void onReceive(Context context, Intent intent) { |
| 73 if (!LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction()))
{ |
| 74 return; |
| 75 } |
| 76 if (checkLocationServicesAndPermission()) { |
| 77 mItemChooserDialog.clear(); |
| 78 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); |
| 79 } |
| 80 } |
| 81 }; |
| 82 |
| 65 // The type of link that is shown within the dialog. | 83 // The type of link that is shown within the dialog. |
| 66 private enum LinkType { | 84 private enum LinkType { |
| 67 EXPLAIN_BLUETOOTH, | 85 EXPLAIN_BLUETOOTH, |
| 68 ADAPTER_OFF, | 86 ADAPTER_OFF, |
| 69 ADAPTER_OFF_HELP, | 87 ADAPTER_OFF_HELP, |
| 70 REQUEST_LOCATION_PERMISSION, | 88 REQUEST_LOCATION_PERMISSION, |
| 89 REQUEST_LOCATION_SERVICES, |
| 71 NEED_LOCATION_PERMISSION_HELP, | 90 NEED_LOCATION_PERMISSION_HELP, |
| 72 RESTART_SEARCH, | 91 RESTART_SEARCH, |
| 73 } | 92 } |
| 74 | 93 |
| 75 /** | 94 /** |
| 76 * Creates the BluetoothChooserDialog. | 95 * Creates the BluetoothChooserDialog. |
| 77 */ | 96 */ |
| 78 @VisibleForTesting | 97 @VisibleForTesting |
| 79 BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int secur
ityLevel, | 98 BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int secur
ityLevel, |
| 80 long nativeBluetoothChooserDialogPtr) { | 99 long nativeBluetoothChooserDialogPtr) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 mActivity.getString(R.string.bluetooth_not_seeing_it_idle_some_f
ound), | 142 mActivity.getString(R.string.bluetooth_not_seeing_it_idle_some_f
ound), |
| 124 new SpanInfo("<link1>", "</link1>", | 143 new SpanInfo("<link1>", "</link1>", |
| 125 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUETOOTH, m
Activity)), | 144 new BluetoothClickableSpan(LinkType.EXPLAIN_BLUETOOTH, m
Activity)), |
| 126 new SpanInfo("<link2>", "</link2>", | 145 new SpanInfo("<link2>", "</link2>", |
| 127 new BluetoothClickableSpan(LinkType.RESTART_SEARCH, mAct
ivity))); | 146 new BluetoothClickableSpan(LinkType.RESTART_SEARCH, mAct
ivity))); |
| 128 | 147 |
| 129 ItemChooserDialog.ItemChooserLabels labels = | 148 ItemChooserDialog.ItemChooserLabels labels = |
| 130 new ItemChooserDialog.ItemChooserLabels(title, searching, noneFo
und, | 149 new ItemChooserDialog.ItemChooserLabels(title, searching, noneFo
und, |
| 131 statusIdleNoneFound, statusIdleSomeFound, positiveButton
); | 150 statusIdleNoneFound, statusIdleSomeFound, positiveButton
); |
| 132 mItemChooserDialog = new ItemChooserDialog(mActivity, this, labels); | 151 mItemChooserDialog = new ItemChooserDialog(mActivity, this, labels); |
| 152 |
| 153 mActivity.registerReceiver(mLocationModeBroadcastReceiver, |
| 154 new IntentFilter(LocationManager.MODE_CHANGED_ACTION)); |
| 155 } |
| 156 |
| 157 // Called to report the dialog's results back to native code. |
| 158 private void finishDialog(int resultCode, String id) { |
| 159 mActivity.unregisterReceiver(mLocationModeBroadcastReceiver); |
| 160 if (mNativeBluetoothChooserDialogPtr != 0) { |
| 161 nativeOnDialogFinished(mNativeBluetoothChooserDialogPtr, resultCode,
id); |
| 162 } |
| 133 } | 163 } |
| 134 | 164 |
| 135 @Override | 165 @Override |
| 136 public void onItemSelected(String id) { | 166 public void onItemSelected(String id) { |
| 137 if (mNativeBluetoothChooserDialogPtr != 0) { | 167 if (id.isEmpty()) { |
| 138 if (id.isEmpty()) { | 168 finishDialog(DIALOG_FINISHED_CANCELLED, ""); |
| 139 nativeOnDialogFinished( | 169 } else { |
| 140 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_CANCEL
LED, ""); | 170 finishDialog(DIALOG_FINISHED_SELECTED, id); |
| 141 } else { | |
| 142 nativeOnDialogFinished( | |
| 143 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_SELECT
ED, id); | |
| 144 } | |
| 145 } | 171 } |
| 146 } | 172 } |
| 147 | 173 |
| 148 @Override | 174 @Override |
| 149 public void onRequestPermissionsResult(String[] permissions, int[] grantResu
lts) { | 175 public void onRequestPermissionsResult(String[] permissions, int[] grantResu
lts) { |
| 150 for (int i = 0; i < grantResults.length; i++) { | 176 for (int i = 0; i < permissions.length; i++) { |
| 151 if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION
)) { | 177 if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION
)) { |
| 152 if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { | 178 if (checkLocationServicesAndPermission()) { |
| 153 mItemChooserDialog.clear(); | 179 mItemChooserDialog.clear(); |
| 154 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); | 180 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); |
| 155 } else { | |
| 156 checkLocationPermission(); | |
| 157 } | 181 } |
| 158 return; | 182 return; |
| 159 } | 183 } |
| 160 } | 184 } |
| 161 // If the location permission is not present, leave the currently-shown
message in place. | 185 // If the location permission is not present, leave the currently-shown
message in place. |
| 162 } | 186 } |
| 163 | 187 |
| 164 private void checkLocationPermission() { | 188 // Returns true if Location Services is on and Chrome has permission to see
the user's location. |
| 165 if (LocationUtils.getInstance().hasAndroidLocationPermission(mActivity))
{ | 189 private boolean checkLocationServicesAndPermission() { |
| 166 return; | 190 final boolean havePermission = |
| 191 LocationUtils.getInstance().hasAndroidLocationPermission(mActivi
ty); |
| 192 final boolean locationServicesOn = |
| 193 LocationUtils.getInstance().isSystemLocationSettingEnabled(mActi
vity); |
| 194 |
| 195 if (!havePermission |
| 196 && !mWindowAndroid.canRequestPermission( |
| 197 Manifest.permission.ACCESS_COARSE_LOCATION)) { |
| 198 // Immediately close the dialog because the user has asked Chrome no
t to request the |
| 199 // location permission. |
| 200 finishDialog(DIALOG_FINISHED_DENIED_PERMISSION, ""); |
| 201 return false; |
| 167 } | 202 } |
| 168 | 203 |
| 169 if (!mWindowAndroid.canRequestPermission(Manifest.permission.ACCESS_COAR
SE_LOCATION)) { | 204 // Compute the message to show the user. |
| 170 if (mNativeBluetoothChooserDialogPtr != 0) { | 205 final SpanInfo permissionSpan = new SpanInfo("<permission_link>", "</per
mission_link>", |
| 171 nativeOnDialogFinished( | 206 new BluetoothClickableSpan(LinkType.REQUEST_LOCATION_PERMISSION,
mActivity)); |
| 172 mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_DENIED
_PERMISSION, ""); | 207 final SpanInfo servicesSpan = new SpanInfo("<services_link>", "</service
s_link>", |
| 173 return; | 208 new BluetoothClickableSpan(LinkType.REQUEST_LOCATION_SERVICES, m
Activity)); |
| 209 final SpannableString needLocationMessage; |
| 210 if (havePermission) { |
| 211 if (locationServicesOn) { |
| 212 // We don't need to request anything. |
| 213 return true; |
| 214 } else { |
| 215 needLocationMessage = SpanApplier.applySpans( |
| 216 mActivity.getString(R.string.bluetooth_need_location_ser
vices_on), |
| 217 servicesSpan); |
| 218 } |
| 219 } else { |
| 220 if (locationServicesOn) { |
| 221 needLocationMessage = SpanApplier.applySpans( |
| 222 mActivity.getString(R.string.bluetooth_need_location_per
mission), |
| 223 permissionSpan); |
| 224 } else { |
| 225 needLocationMessage = SpanApplier.applySpans( |
| 226 mActivity.getString( |
| 227 R.string.bluetooth_need_location_permission_and_
services_on), |
| 228 permissionSpan, servicesSpan); |
| 174 } | 229 } |
| 175 } | 230 } |
| 176 | 231 |
| 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( | 232 SpannableString needLocationStatus = SpanApplier.applySpans( |
| 184 mActivity.getString(R.string.bluetooth_need_location_permission_
help), | 233 mActivity.getString(R.string.bluetooth_need_location_permission_
help), |
| 185 new SpanInfo("<link>", "</link>", | 234 new SpanInfo("<link>", "</link>", |
| 186 new BluetoothClickableSpan( | 235 new BluetoothClickableSpan( |
| 187 LinkType.NEED_LOCATION_PERMISSION_HELP, mAc
tivity))); | 236 LinkType.NEED_LOCATION_PERMISSION_HELP, mAc
tivity))); |
| 188 | 237 |
| 189 mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus
); | 238 mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus
); |
| 239 return false; |
| 190 } | 240 } |
| 191 | 241 |
| 192 private class BluetoothClickableSpan extends NoUnderlineClickableSpan { | 242 private class BluetoothClickableSpan extends NoUnderlineClickableSpan { |
| 193 // The type of link this span represents. | 243 // The type of link this span represents. |
| 194 private LinkType mLinkType; | 244 private LinkType mLinkType; |
| 195 | 245 |
| 196 private Context mContext; | 246 private Context mContext; |
| 197 | 247 |
| 198 BluetoothClickableSpan(LinkType linkType, Context context) { | 248 BluetoothClickableSpan(LinkType linkType, Context context) { |
| 199 mLinkType = linkType; | 249 mLinkType = linkType; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 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( |
| 288 LocationUtils.getInstance().getSystemLocationSetting
sIntent()); |
| 289 break; |
| 290 } |
| 236 case NEED_LOCATION_PERMISSION_HELP: { | 291 case NEED_LOCATION_PERMISSION_HELP: { |
| 237 nativeShowNeedLocationPermissionLink(mNativeBluetoothChooser
DialogPtr); | 292 nativeShowNeedLocationPermissionLink(mNativeBluetoothChooser
DialogPtr); |
| 238 closeDialog(); | 293 closeDialog(); |
| 239 break; | 294 break; |
| 240 } | 295 } |
| 241 case RESTART_SEARCH: { | 296 case RESTART_SEARCH: { |
| 242 mItemChooserDialog.clear(); | 297 mItemChooserDialog.clear(); |
| 243 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); | 298 nativeRestartSearch(mNativeBluetoothChooserDialogPtr); |
| 244 break; | 299 break; |
| 245 } | 300 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 @CalledByNative | 362 @CalledByNative |
| 308 private void notifyAdapterTurnedOn() { | 363 private void notifyAdapterTurnedOn() { |
| 309 mItemChooserDialog.clear(); | 364 mItemChooserDialog.clear(); |
| 310 } | 365 } |
| 311 | 366 |
| 312 @VisibleForTesting | 367 @VisibleForTesting |
| 313 @CalledByNative | 368 @CalledByNative |
| 314 void notifyDiscoveryState(int discoveryState) { | 369 void notifyDiscoveryState(int discoveryState) { |
| 315 switch (discoveryState) { | 370 switch (discoveryState) { |
| 316 case DISCOVERY_FAILED_TO_START: { | 371 case DISCOVERY_FAILED_TO_START: { |
| 317 // FAILED_TO_START might be caused by a missing Location permiss
ion. | 372 // FAILED_TO_START might be caused by a missing Location |
| 373 // permission or by the Location service being turned off. |
| 318 // Check, and show a request if so. | 374 // Check, and show a request if so. |
| 319 checkLocationPermission(); | 375 checkLocationServicesAndPermission(); |
| 320 break; | 376 break; |
| 321 } | 377 } |
| 322 case DISCOVERY_IDLE: { | 378 case DISCOVERY_IDLE: { |
| 323 mItemChooserDialog.setIdleState(); | 379 mItemChooserDialog.setIdleState(); |
| 324 break; | 380 break; |
| 325 } | 381 } |
| 326 default: { | 382 default: { |
| 327 // TODO(jyasskin): Report the new state to the user. | 383 // TODO(jyasskin): Report the new state to the user. |
| 328 break; | 384 break; |
| 329 } | 385 } |
| 330 } | 386 } |
| 331 } | 387 } |
| 332 | 388 |
| 333 @VisibleForTesting | 389 @VisibleForTesting |
| 334 native void nativeOnDialogFinished( | 390 native void nativeOnDialogFinished( |
| 335 long nativeBluetoothChooserAndroid, int eventType, String deviceId); | 391 long nativeBluetoothChooserAndroid, int eventType, String deviceId); |
| 336 @VisibleForTesting | 392 @VisibleForTesting |
| 337 native void nativeRestartSearch(long nativeBluetoothChooserAndroid); | 393 native void nativeRestartSearch(long nativeBluetoothChooserAndroid); |
| 338 // Help links. | 394 // Help links. |
| 339 @VisibleForTesting | 395 @VisibleForTesting |
| 340 native void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndro
id); | 396 native void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndro
id); |
| 341 @VisibleForTesting | 397 @VisibleForTesting |
| 342 native void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAnd
roid); | 398 native void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAnd
roid); |
| 343 @VisibleForTesting | 399 @VisibleForTesting |
| 344 native void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooser
Android); | 400 native void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooser
Android); |
| 345 } | 401 } |
| OLD | NEW |