| /* | |
| * Copyright (C) 2009 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package com.android.settings.bluetooth; | |
| import android.app.Activity; | |
| import android.app.AlertDialog; | |
| import android.bluetooth.BluetoothAdapter; | |
| import android.bluetooth.BluetoothDevice; | |
| import android.content.BroadcastReceiver; | |
| import android.content.Context; | |
| import android.content.DialogInterface; | |
| import android.content.Intent; | |
| import android.content.IntentFilter; | |
| import android.os.Bundle; | |
| import android.util.Log; | |
| import com.android.settings.R; | |
| import com.android.settingslib.bluetooth.BluetoothDiscoverableTimeoutReceiver; | |
| import com.android.settingslib.bluetooth.LocalBluetoothAdapter; | |
| import com.android.settingslib.bluetooth.LocalBluetoothManager; | |
| /** | |
| * RequestPermissionActivity asks the user whether to enable discovery. This is | |
| * usually started by an application wanted to start bluetooth and or discovery | |
| */ | |
| public class RequestPermissionActivity extends Activity implements | |
| DialogInterface.OnClickListener { | |
| // Command line to test this | |
| // adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE | |
| // adb shell am start -a android.bluetooth.adapter.action.REQUEST_DISCOVERABLE | |
| private static final String TAG = "RequestPermissionActivity"; | |
| private static final int MAX_DISCOVERABLE_TIMEOUT = 3600; // 1 hr | |
| // Non-error return code: BT is starting or has started successfully. Used | |
| // by this Activity and RequestPermissionHelperActivity | |
| /* package */ static final int RESULT_BT_STARTING_OR_STARTED = -1000; | |
| private static final int REQUEST_CODE_START_BT = 1; | |
| private LocalBluetoothAdapter mLocalAdapter; | |
| private int mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; | |
| /* | |
| * True if bluetooth wasn't enabled and RequestPermissionHelperActivity was | |
| * started to ask the user and start bt. | |
| * | |
| * If/when that activity returns successfully, display please wait msg then | |
| * go away when bt has started and discovery mode has been enabled. | |
| */ | |
| private boolean mNeededToEnableBluetooth; | |
| // True if requesting BT to be turned on | |
| // False if requesting BT to be turned on + discoverable mode | |
| private boolean mEnableOnly; | |
| private boolean mUserConfirmed; | |
| private AlertDialog mDialog; | |
| private final BroadcastReceiver mReceiver = new BroadcastReceiver() { | |
| @Override | |
| public void onReceive(Context context, Intent intent) { | |
| if (intent == null) { | |
| return; | |
| } | |
| if (mNeededToEnableBluetooth | |
| && BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) { | |
| int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothDevice.ERROR); | |
| if (state == BluetoothAdapter.STATE_ON) { | |
| if (mUserConfirmed) { | |
| proceedAndFinish(); | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| @Override | |
| protected void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| // Note: initializes mLocalAdapter and returns true on error | |
| if (parseIntent()) { | |
| finish(); | |
| return; | |
| } | |
| int btState = mLocalAdapter.getState(); | |
| switch (btState) { | |
| case BluetoothAdapter.STATE_OFF: | |
| case BluetoothAdapter.STATE_TURNING_OFF: | |
| case BluetoothAdapter.STATE_TURNING_ON: | |
| /* | |
| * Strictly speaking STATE_TURNING_ON belong with STATE_ON; | |
| * however, BT may not be ready when the user clicks yes and we | |
| * would fail to turn on discovery mode. By kicking this to the | |
| * RequestPermissionHelperActivity, this class will handle that | |
| * case via the broadcast receiver. | |
| */ | |
| /* | |
| * Start the helper activity to: | |
| * 1) ask the user about enabling bt AND discovery | |
| * 2) enable BT upon confirmation | |
| */ | |
| registerReceiver(mReceiver, | |
| new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); | |
| Intent intent = new Intent(); | |
| intent.setClass(this, RequestPermissionHelperActivity.class); | |
| if (mEnableOnly) { | |
| intent.setAction(RequestPermissionHelperActivity.ACTION_INTERNAL_REQUEST_BT_ON); | |
| } else { | |
| intent.setAction(RequestPermissionHelperActivity. | |
| ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE); | |
| intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, mTimeout); | |
| } | |
| startActivityForResult(intent, REQUEST_CODE_START_BT); | |
| mNeededToEnableBluetooth = true; | |
| break; | |
| case BluetoothAdapter.STATE_ON: | |
| if (mEnableOnly) { | |
| // Nothing to do. Already enabled. | |
| proceedAndFinish(); | |
| } else { | |
| // Ask the user about enabling discovery mode | |
| createDialog(); | |
| } | |
| break; | |
| default: | |
| Log.e(TAG, "Unknown adapter state: " + btState); | |
| } | |
| } | |
| private void createDialog() { | |
| AlertDialog.Builder builder = new AlertDialog.Builder(this); | |
| if (mNeededToEnableBluetooth) { | |
| // RequestPermissionHelperActivity has gotten confirmation from user | |
| // to turn on BT | |
| builder.setMessage(getString(R.string.bluetooth_turning_on)); | |
| builder.setCancelable(false); | |
| } else { | |
| // Ask the user whether to turn on discovery mode or not | |
| // For lasting discoverable mode there is a different message | |
| if (mTimeout == BluetoothDiscoverableEnabler.DISCOVERABLE_TIMEOUT_NEVER) { | |
| builder.setMessage( | |
| getString(R.string.bluetooth_ask_lasting_discovery)); | |
| } else { | |
| builder.setMessage( | |
| getString(R.string.bluetooth_ask_discovery, mTimeout)); | |
| } | |
| builder.setPositiveButton(getString(R.string.allow), this); | |
| builder.setNegativeButton(getString(R.string.deny), this); | |
| } | |
| mDialog = builder.create(); | |
| mDialog.show(); | |
| if (getResources().getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog) == true) { | |
| // dismiss dialog immediately if settings say so | |
| onClick(null, DialogInterface.BUTTON_POSITIVE); | |
| } | |
| } | |
| @Override | |
| protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
| if (requestCode != REQUEST_CODE_START_BT) { | |
| Log.e(TAG, "Unexpected onActivityResult " + requestCode + ' ' + resultCode); | |
| setResult(RESULT_CANCELED); | |
| finish(); | |
| return; | |
| } | |
| if (resultCode != RESULT_BT_STARTING_OR_STARTED) { | |
| setResult(resultCode); | |
| finish(); | |
| return; | |
| } | |
| // Back from RequestPermissionHelperActivity. User confirmed to enable | |
| // BT and discoverable mode. | |
| mUserConfirmed = true; | |
| if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) { | |
| proceedAndFinish(); | |
| } else { | |
| // If BT is not up yet, show "Turning on Bluetooth..." | |
| createDialog(); | |
| } | |
| } | |
| public void onClick(DialogInterface dialog, int which) { | |
| switch (which) { | |
| case DialogInterface.BUTTON_POSITIVE: | |
| proceedAndFinish(); | |
| break; | |
| case DialogInterface.BUTTON_NEGATIVE: | |
| setResult(RESULT_CANCELED); | |
| finish(); | |
| break; | |
| } | |
| } | |
| private void proceedAndFinish() { | |
| int returnCode; | |
| if (mEnableOnly) { | |
| // BT enabled. Done | |
| returnCode = RESULT_OK; | |
| } else if (mLocalAdapter.setScanMode( | |
| BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, mTimeout)) { | |
| // If already in discoverable mode, this will extend the timeout. | |
| long endTime = System.currentTimeMillis() + (long) mTimeout * 1000; | |
| LocalBluetoothPreferences.persistDiscoverableEndTimestamp( | |
| this, endTime); | |
| if (0 < mTimeout) { | |
| BluetoothDiscoverableTimeoutReceiver.setDiscoverableAlarm(this, endTime); | |
| } | |
| returnCode = mTimeout; | |
| // Activity.RESULT_FIRST_USER should be 1 | |
| if (returnCode < RESULT_FIRST_USER) { | |
| returnCode = RESULT_FIRST_USER; | |
| } | |
| } else { | |
| returnCode = RESULT_CANCELED; | |
| } | |
| if (mDialog != null) { | |
| mDialog.dismiss(); | |
| } | |
| setResult(returnCode); | |
| finish(); | |
| } | |
| /** | |
| * Parse the received Intent and initialize mLocalBluetoothAdapter. | |
| * @return true if an error occurred; false otherwise | |
| */ | |
| private boolean parseIntent() { | |
| Intent intent = getIntent(); | |
| if (intent != null && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_ENABLE)) { | |
| mEnableOnly = true; | |
| } else if (intent != null | |
| && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)) { | |
| mTimeout = intent.getIntExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, | |
| BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT); | |
| Log.d(TAG, "Setting Bluetooth Discoverable Timeout = " + mTimeout); | |
| if (mTimeout < 0 || mTimeout > MAX_DISCOVERABLE_TIMEOUT) { | |
| mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; | |
| } | |
| } else { | |
| Log.e(TAG, "Error: this activity may be started only with intent " | |
| + BluetoothAdapter.ACTION_REQUEST_ENABLE + " or " | |
| + BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); | |
| setResult(RESULT_CANCELED); | |
| return true; | |
| } | |
| LocalBluetoothManager manager = Utils.getLocalBtManager(this); | |
| if (manager == null) { | |
| Log.e(TAG, "Error: there's a problem starting Bluetooth"); | |
| setResult(RESULT_CANCELED); | |
| return true; | |
| } | |
| mLocalAdapter = manager.getBluetoothAdapter(); | |
| return false; | |
| } | |
| @Override | |
| protected void onDestroy() { | |
| super.onDestroy(); | |
| if (mNeededToEnableBluetooth) { | |
| unregisterReceiver(mReceiver); | |
| } | |
| } | |
| @Override | |
| public void onBackPressed() { | |
| setResult(RESULT_CANCELED); | |
| super.onBackPressed(); | |
| } | |
| } |