| Index: chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
|
| index 5d96a611012f88400b9c454ec04e1f655eac9fe5..87d9183efbf95e7f52a917846feb11be6040f63f 100644
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
|
| @@ -6,9 +6,11 @@ package org.chromium.chrome.browser;
|
|
|
| import android.Manifest;
|
| import android.app.Activity;
|
| +import android.content.BroadcastReceiver;
|
| import android.content.Context;
|
| import android.content.Intent;
|
| -import android.content.pm.PackageManager;
|
| +import android.content.IntentFilter;
|
| +import android.location.LocationManager;
|
| import android.text.SpannableString;
|
| import android.text.TextUtils;
|
| import android.view.View;
|
| @@ -28,6 +30,8 @@ import org.chromium.ui.text.SpanApplier.SpanInfo;
|
| * A dialog for picking available Bluetooth devices. This dialog is shown when a website requests to
|
| * pair with a certain class of Bluetooth devices (e.g. through a bluetooth.requestDevice Javascript
|
| * call).
|
| + *
|
| + * The dialog is shown by create() or show(), and always runs finishDialog() as it's closing.
|
| */
|
| public class BluetoothChooserDialog
|
| implements ItemChooserDialog.ItemSelectedCallback, WindowAndroid.PermissionCallback {
|
| @@ -68,6 +72,7 @@ public class BluetoothChooserDialog
|
| ADAPTER_OFF,
|
| ADAPTER_OFF_HELP,
|
| REQUEST_LOCATION_PERMISSION,
|
| + REQUEST_LOCATION_SERVICES,
|
| NEED_LOCATION_PERMISSION_HELP,
|
| RESTART_SEARCH,
|
| }
|
| @@ -130,30 +135,35 @@ public class BluetoothChooserDialog
|
| new ItemChooserDialog.ItemChooserLabels(title, searching, noneFound,
|
| statusIdleNoneFound, statusIdleSomeFound, positiveButton);
|
| mItemChooserDialog = new ItemChooserDialog(mActivity, this, labels);
|
| +
|
| + mActivity.registerReceiver(mLocationModeBroadcastReceiver,
|
| + new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
|
| + }
|
| +
|
| + // Called to report the dialog's results back to native code.
|
| + private void finishDialog(int resultCode, String id) {
|
| + mActivity.unregisterReceiver(mLocationModeBroadcastReceiver);
|
| + if (mNativeBluetoothChooserDialogPtr != 0) {
|
| + nativeOnDialogFinished(mNativeBluetoothChooserDialogPtr, resultCode, id);
|
| + }
|
| }
|
|
|
| @Override
|
| public void onItemSelected(String id) {
|
| - if (mNativeBluetoothChooserDialogPtr != 0) {
|
| - if (id.isEmpty()) {
|
| - nativeOnDialogFinished(
|
| - mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_CANCELLED, "");
|
| - } else {
|
| - nativeOnDialogFinished(
|
| - mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_SELECTED, id);
|
| - }
|
| + if (id.isEmpty()) {
|
| + finishDialog(DIALOG_FINISHED_CANCELLED, "");
|
| + } else {
|
| + finishDialog(DIALOG_FINISHED_SELECTED, id);
|
| }
|
| }
|
|
|
| @Override
|
| public void onRequestPermissionsResult(String[] permissions, int[] grantResults) {
|
| - for (int i = 0; i < grantResults.length; i++) {
|
| + for (int i = 0; i < permissions.length; i++) {
|
| if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
|
| - if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
|
| + if (checkLocationServicesAndPermission()) {
|
| mItemChooserDialog.clear();
|
| nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
|
| - } else {
|
| - checkLocationPermission();
|
| }
|
| return;
|
| }
|
| @@ -161,24 +171,62 @@ public class BluetoothChooserDialog
|
| // If the location permission is not present, leave the currently-shown message in place.
|
| }
|
|
|
| - private void checkLocationPermission() {
|
| - if (LocationUtils.getInstance().hasAndroidLocationPermission(mActivity)) {
|
| - return;
|
| - }
|
| -
|
| - if (!mWindowAndroid.canRequestPermission(Manifest.permission.ACCESS_COARSE_LOCATION)) {
|
| - if (mNativeBluetoothChooserDialogPtr != 0) {
|
| - nativeOnDialogFinished(
|
| - mNativeBluetoothChooserDialogPtr, DIALOG_FINISHED_DENIED_PERMISSION, "");
|
| - return;
|
| + @VisibleForTesting
|
| + final BroadcastReceiver mLocationModeBroadcastReceiver = new BroadcastReceiver() {
|
| + @Override
|
| + public void onReceive(Context context, Intent intent) {
|
| + if (LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction())) {
|
| + if (checkLocationServicesAndPermission()) {
|
| + mItemChooserDialog.clear();
|
| + nativeRestartSearch(mNativeBluetoothChooserDialogPtr);
|
| + }
|
| }
|
| }
|
| + };
|
|
|
| - SpannableString needLocationMessage = SpanApplier.applySpans(
|
| - mActivity.getString(R.string.bluetooth_need_location_permission),
|
| - new SpanInfo("<link>", "</link>",
|
| - new BluetoothClickableSpan(
|
| - LinkType.REQUEST_LOCATION_PERMISSION, mActivity)));
|
| + // Returns true if Location Services is on and Chrome has permission to see the user's location.
|
| + private boolean checkLocationServicesAndPermission() {
|
| + final boolean havePermission =
|
| + LocationUtils.getInstance().hasAndroidLocationPermission(mActivity);
|
| + final boolean locationServicesOn =
|
| + LocationUtils.getInstance().isSystemLocationSettingEnabled(mActivity);
|
| +
|
| + if (!havePermission
|
| + && !mWindowAndroid.canRequestPermission(
|
| + Manifest.permission.ACCESS_COARSE_LOCATION)) {
|
| + // Immediately close the dialog because the user has asked Chrome not to request the
|
| + // location permission.
|
| + finishDialog(DIALOG_FINISHED_DENIED_PERMISSION, "");
|
| + return false;
|
| + }
|
| +
|
| + // Compute the message to show the user.
|
| + final SpanInfo permissionSpan = new SpanInfo("<permission_link>", "</permission_link>",
|
| + new BluetoothClickableSpan(LinkType.REQUEST_LOCATION_PERMISSION, mActivity));
|
| + final SpanInfo servicesSpan = new SpanInfo("<services_link>", "</services_link>",
|
| + new BluetoothClickableSpan(LinkType.REQUEST_LOCATION_SERVICES, mActivity));
|
| + final SpannableString needLocationMessage;
|
| + if (havePermission) {
|
| + if (locationServicesOn) {
|
| + // We don't need to request anything.
|
| + return true;
|
| + } else {
|
| + needLocationMessage = SpanApplier.applySpans(
|
| + mActivity.getString(R.string.bluetooth_need_location_services_on),
|
| + servicesSpan);
|
| + }
|
| + } else {
|
| + if (locationServicesOn) {
|
| + needLocationMessage = SpanApplier.applySpans(
|
| + mActivity.getString(R.string.bluetooth_need_location_permission),
|
| + permissionSpan);
|
| + } else {
|
| + needLocationMessage = SpanApplier.applySpans(
|
| + mActivity.getString(
|
| + R.string.bluetooth_need_location_permission_and_services_on),
|
| + permissionSpan, servicesSpan);
|
| + }
|
| + }
|
|
|
| SpannableString needLocationStatus = SpanApplier.applySpans(
|
| mActivity.getString(R.string.bluetooth_need_location_permission_help),
|
| @@ -187,6 +235,7 @@ public class BluetoothChooserDialog
|
| LinkType.NEED_LOCATION_PERMISSION_HELP, mActivity)));
|
|
|
| mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus);
|
| + return false;
|
| }
|
|
|
| private class BluetoothClickableSpan extends NoUnderlineClickableSpan {
|
| @@ -233,6 +282,11 @@ public class BluetoothChooserDialog
|
| BluetoothChooserDialog.this);
|
| break;
|
| }
|
| + case REQUEST_LOCATION_SERVICES: {
|
| + mContext.startActivity(
|
| + LocationUtils.getInstance().getSystemLocationSettingsIntent());
|
| + break;
|
| + }
|
| case NEED_LOCATION_PERMISSION_HELP: {
|
| nativeShowNeedLocationPermissionLink(mNativeBluetoothChooserDialogPtr);
|
| closeDialog();
|
| @@ -317,9 +371,10 @@ public class BluetoothChooserDialog
|
| void notifyDiscoveryState(int discoveryState) {
|
| switch (discoveryState) {
|
| case DISCOVERY_FAILED_TO_START: {
|
| - // FAILED_TO_START might be caused by a missing Location permission.
|
| + // FAILED_TO_START might be caused by a missing Location
|
| + // permission or by the Location service being turned off.
|
| // Check, and show a request if so.
|
| - checkLocationPermission();
|
| + checkLocationServicesAndPermission();
|
| break;
|
| }
|
| case DISCOVERY_IDLE: {
|
|
|