Chromium Code Reviews| 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 3483a645626c69f58936686326bf4dde328c5443..834701f7f1fc0240ed24a1e765f86457adcea11d 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,12 @@ 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.provider.Settings; |
| import android.text.SpannableString; |
| import android.text.TextUtils; |
| import android.view.View; |
| @@ -17,6 +20,7 @@ import org.chromium.base.VisibleForTesting; |
| import org.chromium.base.annotations.CalledByNative; |
| import org.chromium.chrome.R; |
| import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer; |
| +import org.chromium.chrome.browser.preferences.LocationSettings; |
| import org.chromium.chrome.browser.profiles.Profile; |
| import org.chromium.ui.base.WindowAndroid; |
| import org.chromium.ui.text.NoUnderlineClickableSpan; |
| @@ -27,6 +31,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 { |
| @@ -67,6 +73,7 @@ public class BluetoothChooserDialog |
| ADAPTER_OFF, |
| ADAPTER_OFF_HELP, |
| REQUEST_LOCATION_PERMISSION, |
| + REQUEST_LOCATION_SERVICES, |
| NEED_LOCATION_PERMISSION_HELP, |
| RESTART_SEARCH, |
| } |
| @@ -129,30 +136,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; |
| } |
| @@ -160,25 +172,63 @@ public class BluetoothChooserDialog |
| // If the location permission is not present, leave the currently-shown message in place. |
| } |
| - private void checkLocationPermission() { |
| - if (mWindowAndroid.hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION) |
| - || mWindowAndroid.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) { |
| - 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 = |
| + mWindowAndroid.hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION) |
| + || mWindowAndroid.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION); |
| + final boolean locationServicesOn = |
| + 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.
|
| + |
| + 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 +237,7 @@ public class BluetoothChooserDialog |
| LinkType.NEED_LOCATION_PERMISSION_HELP, mActivity))); |
| mItemChooserDialog.setErrorState(needLocationMessage, needLocationStatus); |
| + return false; |
| } |
| private class BluetoothClickableSpan extends NoUnderlineClickableSpan { |
| @@ -217,9 +268,8 @@ public class BluetoothChooserDialog |
| break; |
| } |
| case ADAPTER_OFF: { |
| - Intent intent = new Intent(); |
| - intent.setAction(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS); |
| - mContext.startActivity(intent); |
| + mContext.startActivity( |
| + new Intent(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS)); |
| break; |
| } |
| case ADAPTER_OFF_HELP: { |
| @@ -233,6 +283,10 @@ public class BluetoothChooserDialog |
| BluetoothChooserDialog.this); |
| break; |
| } |
| + case REQUEST_LOCATION_SERVICES: { |
| + mContext.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); |
| + 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: { |