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 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 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 178 @Override 179 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 180 if (requestCode != REQUEST_CODE_START_BT) { 181 Log.e(TAG, "Unexpected onActivityResult " + requestCode + ' ' + resultCode); 182 setResult(RESULT_CANCELED); 183 finish(); 184 return; 185 } 186 if (resultCode != RESULT_BT_STARTING_OR_STARTED) { 187 setResult(resultCode); 188 finish(); 189 return; 190 } 191 192 // Back from RequestPermissionHelperActivity. User confirmed to enable 193 // BT and discoverable mode. 194 mUserConfirmed = true; 195 196 if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) { 197 proceedAndFinish(); 198 } else { 199 // If BT is not up yet, show "Turning on Bluetooth..." 200 createDialog(); 201 } 202 } 203 204 public void onClick(DialogInterface dialog, int which) { 205 switch (which) { 206 case DialogInterface.BUTTON_POSITIVE: 207 proceedAndFinish(); 208 break; 209 210 case DialogInterface.BUTTON_NEGATIVE: 211 setResult(RESULT_CANCELED); 212 finish(); 213 break; 214 } 215 } 216 217 private void proceedAndFinish() { 218 int returnCode; 219 220 if (mEnableOnly) { 221 // BT enabled. Done 222 returnCode = RESULT_OK; 223 } else if (mLocalAdapter.setScanMode( 224 BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, mTimeout)) { 225 // If already in discoverable mode, this will extend the timeout. 226 LocalBluetoothPreferences.persistDiscoverableEndTimestamp( 227 this, System.currentTimeMillis() + (long) mTimeout * 1000); 228 returnCode = mTimeout; 229 // Activity.RESULT_FIRST_USER should be 1 230 if (returnCode < RESULT_FIRST_USER) { 231 returnCode = RESULT_FIRST_USER; 232 } 233 } else { 234 returnCode = RESULT_CANCELED; 235 } 236 237 if (mDialog != null) { 238 mDialog.dismiss(); 239 } 240 241 setResult(returnCode); 242 finish(); 243 } 244 245 /** 246 * Parse the received Intent and initialize mLocalBluetoothAdapter. 247 * @return true if an error occurred; false otherwise 248 */ 249 private boolean parseIntent() { 250 Intent intent = getIntent(); 251 if (intent != null && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_ENABLE)) { 252 mEnableOnly = true; 253 } else if (intent != null 254 && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)) { 255 mTimeout = intent.getIntExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 256 BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT); 257 258 Log.d(TAG, "Setting Bluetooth Discoverable Timeout = " + mTimeout); 259 260 if (mTimeout < 0 || mTimeout > MAX_DISCOVERABLE_TIMEOUT) { 261 mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; 262 } 263 } else { 264 Log.e(TAG, "Error: this activity may be started only with intent " 265 + BluetoothAdapter.ACTION_REQUEST_ENABLE + " or " 266 + BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); 267 setResult(RESULT_CANCELED); 268 return true; 269 } 270 271 LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this); 272 if (manager == null) { 273 Log.e(TAG, "Error: there's a problem starting Bluetooth"); 274 setResult(RESULT_CANCELED); 275 return true; 276 } 277 mLocalAdapter = manager.getBluetoothAdapter(); 278 279 return false; 280 } 281 282 @Override 283 protected void onDestroy() { 284 super.onDestroy(); 285 if (mNeededToEnableBluetooth) { 286 unregisterReceiver(mReceiver); 287 } 288 } 289 290 @Override 291 public void onBackPressed() { 292 setResult(RESULT_CANCELED); 293 super.onBackPressed(); 294 } 295 } 296