1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.bluetooth; 18 19 import com.android.settings.R; 20 21 import android.app.Activity; 22 import android.app.AlertDialog; 23 import android.bluetooth.BluetoothAdapter; 24 import android.bluetooth.BluetoothDevice; 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.DialogInterface; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.os.Bundle; 31 import android.util.Log; 32 33 /** 34 * RequestPermissionActivity asks the user whether to enable discovery. This is 35 * usually started by an application wanted to start bluetooth and or discovery 36 */ 37 public class RequestPermissionActivity extends Activity implements 38 DialogInterface.OnClickListener { 39 // Command line to test this 40 // adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE 41 // adb shell am start -a android.bluetooth.adapter.action.REQUEST_DISCOVERABLE 42 43 private static final String TAG = "RequestPermissionActivity"; 44 45 private static final int MAX_DISCOVERABLE_TIMEOUT = 3600; // 1 hr 46 47 // Non-error return code: BT is starting or has started successfully. Used 48 // by this Activity and RequestPermissionHelperActivity 49 /* package */ static final int RESULT_BT_STARTING_OR_STARTED = -1000; 50 51 private static final int REQUEST_CODE_START_BT = 1; 52 53 private LocalBluetoothAdapter mLocalAdapter; 54 55 private int mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; 56 57 /* 58 * True if bluetooth wasn't enabled and RequestPermissionHelperActivity was 59 * started to ask the user and start bt. 60 * 61 * If/when that activity returns successfully, display please wait msg then 62 * go away when bt has started and discovery mode has been enabled. 63 */ 64 private boolean mNeededToEnableBluetooth; 65 66 // True if requesting BT to be turned on 67 // False if requesting BT to be turned on + discoverable mode 68 private boolean mEnableOnly; 69 70 private boolean mUserConfirmed; 71 72 private AlertDialog mDialog; 73 74 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 75 76 @Override 77 public void onReceive(Context context, Intent intent) { 78 if (intent == null) { 79 return; 80 } 81 if (mNeededToEnableBluetooth 82 && BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) { 83 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothDevice.ERROR); 84 if (state == BluetoothAdapter.STATE_ON) { 85 if (mUserConfirmed) { 86 proceedAndFinish(); 87 } 88 } 89 } 90 } 91 }; 92 93 @Override onCreate(Bundle savedInstanceState)94 protected void onCreate(Bundle savedInstanceState) { 95 super.onCreate(savedInstanceState); 96 97 // Note: initializes mLocalAdapter and returns true on error 98 if (parseIntent()) { 99 finish(); 100 return; 101 } 102 103 int btState = mLocalAdapter.getState(); 104 105 switch (btState) { 106 case BluetoothAdapter.STATE_OFF: 107 case BluetoothAdapter.STATE_TURNING_OFF: 108 case BluetoothAdapter.STATE_TURNING_ON: 109 /* 110 * Strictly speaking STATE_TURNING_ON belong with STATE_ON; 111 * however, BT may not be ready when the user clicks yes and we 112 * would fail to turn on discovery mode. By kicking this to the 113 * RequestPermissionHelperActivity, this class will handle that 114 * case via the broadcast receiver. 115 */ 116 117 /* 118 * Start the helper activity to: 119 * 1) ask the user about enabling bt AND discovery 120 * 2) enable BT upon confirmation 121 */ 122 registerReceiver(mReceiver, 123 new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); 124 Intent intent = new Intent(); 125 intent.setClass(this, RequestPermissionHelperActivity.class); 126 if (mEnableOnly) { 127 intent.setAction(RequestPermissionHelperActivity.ACTION_INTERNAL_REQUEST_BT_ON); 128 } else { 129 intent.setAction(RequestPermissionHelperActivity. 130 ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE); 131 intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, mTimeout); 132 } 133 startActivityForResult(intent, REQUEST_CODE_START_BT); 134 mNeededToEnableBluetooth = true; 135 break; 136 case BluetoothAdapter.STATE_ON: 137 if (mEnableOnly) { 138 // Nothing to do. Already enabled. 139 proceedAndFinish(); 140 } else { 141 // Ask the user about enabling discovery mode 142 createDialog(); 143 } 144 break; 145 default: 146 Log.e(TAG, "Unknown adapter state: " + btState); 147 } 148 } 149 createDialog()150 private void createDialog() { 151 AlertDialog.Builder builder = new AlertDialog.Builder(this); 152 builder.setIcon(android.R.drawable.ic_dialog_info); 153 builder.setTitle(getString(R.string.bluetooth_permission_request)); 154 155 if (mNeededToEnableBluetooth) { 156 // RequestPermissionHelperActivity has gotten confirmation from user 157 // to turn on BT 158 builder.setMessage(getString(R.string.bluetooth_turning_on)); 159 builder.setCancelable(false); 160 } else { 161 // Ask the user whether to turn on discovery mode or not 162 // For lasting discoverable mode there is a different message 163 if (mTimeout == BluetoothDiscoverableEnabler.DISCOVERABLE_TIMEOUT_NEVER) { 164 builder.setMessage( 165 getString(R.string.bluetooth_ask_lasting_discovery)); 166 } else { 167 builder.setMessage( 168 getString(R.string.bluetooth_ask_discovery, mTimeout)); 169 } 170 builder.setPositiveButton(getString(R.string.yes), this); 171 builder.setNegativeButton(getString(R.string.no), this); 172 } 173 174 mDialog = builder.create(); 175 mDialog.show(); 176 177 if (getResources().getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog) == true) { 178 // dismiss dialog immediately if settings say so 179 onClick(null, DialogInterface.BUTTON_POSITIVE); 180 } 181 } 182 183 @Override onActivityResult(int requestCode, int resultCode, Intent data)184 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 185 if (requestCode != REQUEST_CODE_START_BT) { 186 Log.e(TAG, "Unexpected onActivityResult " + requestCode + ' ' + resultCode); 187 setResult(RESULT_CANCELED); 188 finish(); 189 return; 190 } 191 if (resultCode != RESULT_BT_STARTING_OR_STARTED) { 192 setResult(resultCode); 193 finish(); 194 return; 195 } 196 197 // Back from RequestPermissionHelperActivity. User confirmed to enable 198 // BT and discoverable mode. 199 mUserConfirmed = true; 200 201 if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) { 202 proceedAndFinish(); 203 } else { 204 // If BT is not up yet, show "Turning on Bluetooth..." 205 createDialog(); 206 } 207 } 208 onClick(DialogInterface dialog, int which)209 public void onClick(DialogInterface dialog, int which) { 210 switch (which) { 211 case DialogInterface.BUTTON_POSITIVE: 212 proceedAndFinish(); 213 break; 214 215 case DialogInterface.BUTTON_NEGATIVE: 216 setResult(RESULT_CANCELED); 217 finish(); 218 break; 219 } 220 } 221 proceedAndFinish()222 private void proceedAndFinish() { 223 int returnCode; 224 225 if (mEnableOnly) { 226 // BT enabled. Done 227 returnCode = RESULT_OK; 228 } else if (mLocalAdapter.setScanMode( 229 BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, mTimeout)) { 230 // If already in discoverable mode, this will extend the timeout. 231 LocalBluetoothPreferences.persistDiscoverableEndTimestamp( 232 this, System.currentTimeMillis() + (long) mTimeout * 1000); 233 returnCode = mTimeout; 234 // Activity.RESULT_FIRST_USER should be 1 235 if (returnCode < RESULT_FIRST_USER) { 236 returnCode = RESULT_FIRST_USER; 237 } 238 } else { 239 returnCode = RESULT_CANCELED; 240 } 241 242 if (mDialog != null) { 243 mDialog.dismiss(); 244 } 245 246 setResult(returnCode); 247 finish(); 248 } 249 250 /** 251 * Parse the received Intent and initialize mLocalBluetoothAdapter. 252 * @return true if an error occurred; false otherwise 253 */ parseIntent()254 private boolean parseIntent() { 255 Intent intent = getIntent(); 256 if (intent != null && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_ENABLE)) { 257 mEnableOnly = true; 258 } else if (intent != null 259 && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)) { 260 mTimeout = intent.getIntExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 261 BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT); 262 263 Log.d(TAG, "Setting Bluetooth Discoverable Timeout = " + mTimeout); 264 265 if (mTimeout < 0 || mTimeout > MAX_DISCOVERABLE_TIMEOUT) { 266 mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; 267 } 268 } else { 269 Log.e(TAG, "Error: this activity may be started only with intent " 270 + BluetoothAdapter.ACTION_REQUEST_ENABLE + " or " 271 + BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); 272 setResult(RESULT_CANCELED); 273 return true; 274 } 275 276 LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this); 277 if (manager == null) { 278 Log.e(TAG, "Error: there's a problem starting Bluetooth"); 279 setResult(RESULT_CANCELED); 280 return true; 281 } 282 mLocalAdapter = manager.getBluetoothAdapter(); 283 284 return false; 285 } 286 287 @Override onDestroy()288 protected void onDestroy() { 289 super.onDestroy(); 290 if (mNeededToEnableBluetooth) { 291 unregisterReceiver(mReceiver); 292 } 293 } 294 295 @Override onBackPressed()296 public void onBackPressed() { 297 setResult(RESULT_CANCELED); 298 super.onBackPressed(); 299 } 300 } 301