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