• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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