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.content.SharedPreferences; 31 import android.os.Bundle; 32 import android.util.Log; 33 34 /** 35 * RequestPermissionActivity asks the user whether to enable discovery. This is 36 * usually started by an application wanted to start bluetooth and or discovery 37 */ 38 public class RequestPermissionActivity extends Activity implements 39 DialogInterface.OnClickListener { 40 // Command line to test this 41 // adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE 42 // adb shell am start -a android.bluetooth.adapter.action.REQUEST_DISCOVERABLE 43 44 private static final String TAG = "RequestPermissionActivity"; 45 46 private static final int MAX_DISCOVERABLE_TIMEOUT = 300; 47 48 // Non-error return code: BT is starting or has started successfully. Used 49 // by this Activity and RequestPermissionHelperActivity 50 /* package */ static final int RESULT_BT_STARTING_OR_STARTED = -1000; 51 52 private static final int REQUEST_CODE_START_BT = 1; 53 54 private LocalBluetoothManager mLocalManager; 55 56 private int mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; 57 58 /* 59 * True if bluetooth wasn't enabled and RequestPermissionHelperActivity was 60 * started to ask the user and start bt. 61 * 62 * If/when that activity returns successfully, display please wait msg then 63 * go away when bt has started and discovery mode has been enabled. 64 */ 65 private boolean mNeededToEnableBluetooth; 66 67 // True if requesting BT to be turned on 68 // False if requesting BT to be turned on + discoverable mode 69 private boolean mEnableOnly = false; 70 71 private boolean mUserConfirmed = false; 72 73 private AlertDialog mDialog = null; 74 75 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 76 77 @Override 78 public void onReceive(Context context, Intent intent) { 79 if (intent == null) 80 return; 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 if (parseIntent()) { 98 finish(); 99 return; 100 } 101 102 int btState = mLocalManager.getBluetoothState(); 103 104 switch (btState) { 105 case BluetoothAdapter.STATE_OFF: 106 case BluetoothAdapter.STATE_TURNING_OFF: 107 case BluetoothAdapter.STATE_TURNING_ON: 108 /* 109 * Strictly speaking STATE_TURNING_ON belong with STATE_ON; 110 * however, BT may not be ready when the user clicks yes and we 111 * would fail to turn on discovery mode. By kicking this to the 112 * RequestPermissionHelperActivity, this class will handle that 113 * case via the broadcast receiver. 114 */ 115 116 /* 117 * Start the helper activity to: 118 * 1) ask the user about enabling bt AND discovery 119 * 2) enable BT upon confirmation 120 */ 121 registerReceiver(mReceiver, 122 new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); 123 Intent i = new Intent(); 124 i.setClass(this, RequestPermissionHelperActivity.class); 125 if (mEnableOnly) { 126 i.setAction(RequestPermissionHelperActivity.ACTION_INTERNAL_REQUEST_BT_ON); 127 } else { 128 i.setAction(RequestPermissionHelperActivity. 129 ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE); 130 i.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, mTimeout); 131 } 132 startActivityForResult(i, REQUEST_CODE_START_BT); 133 mNeededToEnableBluetooth = true; 134 break; 135 case BluetoothAdapter.STATE_ON: 136 if (mEnableOnly) { 137 // Nothing to do. Already enabled. 138 proceedAndFinish(); 139 return; 140 } else { 141 // Ask the user about enabling discovery mode 142 createDialog(); 143 break; 144 } 145 } 146 } 147 148 private void createDialog() { 149 AlertDialog.Builder builder = new AlertDialog.Builder(this); 150 builder.setIcon(android.R.drawable.ic_dialog_info); 151 builder.setTitle(getString(R.string.bluetooth_permission_request)); 152 153 if (mNeededToEnableBluetooth) { 154 // RequestPermissionHelperActivity has gotten confirmation from user 155 // to turn on BT 156 builder.setMessage(getString(R.string.bluetooth_turning_on)); 157 builder.setCancelable(false); 158 } else { 159 // Ask the user whether to turn on discovery mode or not 160 builder.setMessage(getString(R.string.bluetooth_ask_enablement_and_discovery, mTimeout)); 161 builder.setPositiveButton(getString(R.string.yes), this); 162 builder.setNegativeButton(getString(R.string.no), this); 163 } 164 165 mDialog = builder.create(); 166 mDialog.show(); 167 } 168 169 @Override 170 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 171 if (requestCode != REQUEST_CODE_START_BT) { 172 Log.e(TAG, "Unexpected onActivityResult " + requestCode + " " + resultCode); 173 setResult(Activity.RESULT_CANCELED); 174 finish(); 175 return; 176 } 177 if (resultCode != RESULT_BT_STARTING_OR_STARTED) { 178 setResult(resultCode); 179 finish(); 180 return; 181 } 182 183 // Back from RequestPermissionHelperActivity. User confirmed to enable 184 // BT and discoverable mode. 185 mUserConfirmed = true; 186 187 if (mLocalManager.getBluetoothState() == BluetoothAdapter.STATE_ON) { 188 proceedAndFinish(); 189 } else { 190 // If BT is not up yet, show "Turning on Bluetooth..." 191 createDialog(); 192 } 193 } 194 195 public void onClick(DialogInterface dialog, int which) { 196 switch (which) { 197 case DialogInterface.BUTTON_POSITIVE: 198 proceedAndFinish(); 199 break; 200 201 case DialogInterface.BUTTON_NEGATIVE: 202 setResult(Activity.RESULT_CANCELED); 203 finish(); 204 break; 205 } 206 } 207 208 private void proceedAndFinish() { 209 int returnCode; 210 211 if (mEnableOnly) { 212 // BT enabled. Done 213 returnCode = Activity.RESULT_OK; 214 } else if (mLocalManager.getBluetoothAdapter().setScanMode( 215 BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, mTimeout)) { 216 // If already in discoverable mode, this will extend the timeout. 217 persistDiscoverableEndTimestamp(System.currentTimeMillis() + mTimeout * 1000); 218 returnCode = mTimeout; 219 // Activity.RESULT_FIRST_USER should be 1 220 if (returnCode < Activity.RESULT_FIRST_USER) { 221 returnCode = Activity.RESULT_FIRST_USER; 222 } 223 } else { 224 returnCode = Activity.RESULT_CANCELED; 225 } 226 227 if (mDialog != null) { 228 mDialog.dismiss(); 229 } 230 231 setResult(returnCode); 232 finish(); 233 } 234 235 private boolean parseIntent() { 236 Intent intent = getIntent(); 237 if (intent != null && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_ENABLE)) { 238 mEnableOnly = true; 239 } else if (intent != null 240 && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)) { 241 mTimeout = intent.getIntExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 242 BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT); 243 244 Log.e(TAG, "Timeout = " + mTimeout); 245 246 if (mTimeout > MAX_DISCOVERABLE_TIMEOUT) { 247 mTimeout = MAX_DISCOVERABLE_TIMEOUT; 248 } else if (mTimeout <= 0) { 249 mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; 250 } 251 } else { 252 Log.e(TAG, "Error: this activity may be started only with intent " 253 + BluetoothAdapter.ACTION_REQUEST_ENABLE + " or " 254 + BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); 255 setResult(Activity.RESULT_CANCELED); 256 return true; 257 } 258 259 mLocalManager = LocalBluetoothManager.getInstance(this); 260 if (mLocalManager == null) { 261 Log.e(TAG, "Error: there's a problem starting bluetooth"); 262 setResult(Activity.RESULT_CANCELED); 263 return true; 264 } 265 266 return false; 267 } 268 269 @Override 270 protected void onDestroy() { 271 super.onDestroy(); 272 if (mNeededToEnableBluetooth) unregisterReceiver(mReceiver); 273 } 274 275 private void persistDiscoverableEndTimestamp(long endTimestamp) { 276 SharedPreferences.Editor editor = mLocalManager.getSharedPreferences().edit(); 277 editor.putLong( 278 BluetoothDiscoverableEnabler.SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, 279 endTimestamp); 280 editor.commit(); 281 } 282 283 @Override 284 public void onBackPressed() { 285 setResult(Activity.RESULT_CANCELED); 286 super.onBackPressed(); 287 } 288 } 289