2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.bluetooth;
19 import android.app.Notification;
20 import android.app.NotificationManager;
21 import android.app.PendingIntent;
22 import android.bluetooth.BluetoothDevice;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.os.PowerManager;
27 import android.util.Log;
29 import com.android.settings.R;
32 * BluetoothPermissionRequest is a receiver to receive Bluetooth connection
35 public final class BluetoothPermissionRequest extends BroadcastReceiver {
37 private static final String TAG = "BluetoothPermissionRequest";
38 private static final boolean DEBUG = Utils.V;
39 private static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth;
41 private static final String NOTIFICATION_TAG_PBAP = "Phonebook Access" ;
42 private static final String NOTIFICATION_TAG_MAP = "Message Access";
47 BluetoothDevice mDevice;
48 String mReturnPackage = null;
49 String mReturnClass = null;
52 public void onReceive(Context context, Intent intent) {
54 String action = intent.getAction();
56 if (DEBUG) Log.d(TAG, "onReceive" + action);
58 if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) {
59 // convert broadcast intent into activity intent (same action string)
60 mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
61 mRequestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
62 BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION);
63 mReturnPackage = intent.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME);
64 mReturnClass = intent.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME);
66 if (DEBUG) Log.d(TAG, "onReceive request type: " + mRequestType + " return "
67 + mReturnPackage + "," + mReturnClass);
69 // Check if user had made decisions on accepting or rejecting the phonebook access
70 // request. If there is, reply the request and return, no need to start permission
71 // activity dialog or notification.
72 if (checkUserChoice()) {
76 Intent connectionAccessIntent = new Intent(action);
77 connectionAccessIntent.setClass(context, BluetoothPermissionActivity.class);
78 // We use the FLAG_ACTIVITY_MULTIPLE_TASK since we can have multiple concurrent access requests
79 connectionAccessIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
80 connectionAccessIntent.setType(Integer.toString(mRequestType)); /* This is needed to create two pending
81 intents to the same activity.
82 The value is not used in the activity. */
83 connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
85 connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
86 connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, mReturnPackage);
87 connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_CLASS_NAME, mReturnClass);
89 String deviceAddress = mDevice != null ? mDevice.getAddress() : null;
91 String message = null;
92 PowerManager powerManager =
93 (PowerManager) context.getSystemService(Context.POWER_SERVICE);
95 if (powerManager.isScreenOn() &&
96 LocalBluetoothPreferences.shouldShowDialogInForeground(context, deviceAddress) ) {
97 context.startActivity(connectionAccessIntent);
99 // Put up a notification that leads to the dialog
101 // Create an intent triggered by clicking on the
102 // "Clear All Notifications" button
104 Intent deleteIntent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
105 deleteIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
106 deleteIntent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
107 BluetoothDevice.CONNECTION_ACCESS_NO);
108 deleteIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, mRequestType);
109 String deviceName = mDevice != null ? mDevice.getAliasName() : null;
110 switch (mRequestType) {
111 case BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS:
112 title = context.getString(R.string.bluetooth_phonebook_request);
113 message = context.getString(R.string.bluetooth_pb_acceptance_dialog_text, deviceName, deviceName);
115 case BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS:
116 title = context.getString(R.string.bluetooth_map_request);
117 message = context.getString(R.string.bluetooth_map_acceptance_dialog_text, deviceName, deviceName);
120 title = context.getString(R.string.bluetooth_connection_permission_request);
121 message = context.getString(R.string.bluetooth_connection_dialog_text, deviceName, deviceName);
124 Notification notification = new Notification.Builder(context)
125 .setContentTitle(title)
127 .setContentText(message)
128 .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
130 .setPriority(Notification.PRIORITY_MAX)
131 .setOnlyAlertOnce(false)
132 .setDefaults(Notification.DEFAULT_ALL)
133 .setContentIntent(PendingIntent.getActivity(context, 0,
134 connectionAccessIntent, 0))
135 .setDeleteIntent(PendingIntent.getBroadcast(context, 0, deleteIntent, 0))
136 .setColor(context.getResources().getColor(
137 com.android.internal.R.color.system_notification_accent_color))
140 notification.flags |= Notification.FLAG_NO_CLEAR; /* cannot be set with the builder */
142 NotificationManager notificationManager =
143 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
145 notificationManager.notify(getNotificationTag(mRequestType),NOTIFICATION_ID, notification);
147 } else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)) {
148 // Remove the notification
149 NotificationManager manager = (NotificationManager) context
150 .getSystemService(Context.NOTIFICATION_SERVICE);
151 mRequestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
152 BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
153 manager.cancel(getNotificationTag(mRequestType), NOTIFICATION_ID);
157 private String getNotificationTag(int requestType) {
158 if(requestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) {
159 return NOTIFICATION_TAG_PBAP;
160 } else if(mRequestType == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) {
161 return NOTIFICATION_TAG_MAP;
167 * @return true user had made a choice, this method replies to the request according
168 * to user's previous decision
169 * false user hadnot made any choice on this device
171 private boolean checkUserChoice() {
172 boolean processed = false;
174 // ignore if it is something else than phonebook/message settings it wants us to remember
175 if (mRequestType != BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS
176 && mRequestType != BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) {
177 if (DEBUG) Log.d(TAG, "Unknown RequestType: " + mRequestType);
181 LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(mContext);
182 CachedBluetoothDeviceManager cachedDeviceManager =
183 bluetoothManager.getCachedDeviceManager();
184 CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice);
186 if (cachedDevice == null) {
187 cachedDevice = cachedDeviceManager.addDevice(bluetoothManager.getBluetoothAdapter(),
188 bluetoothManager.getProfileManager(), mDevice);
191 if(mRequestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) {
193 int phonebookPermission = cachedDevice.getPhonebookPermissionChoice();
195 if (phonebookPermission == CachedBluetoothDevice.ACCESS_UNKNOWN) {
199 String intentName = BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY;
200 if (phonebookPermission == CachedBluetoothDevice.ACCESS_ALLOWED) {
201 sendIntentToReceiver(intentName, true, BluetoothDevice.EXTRA_ALWAYS_ALLOWED, true);
203 } else if (phonebookPermission == CachedBluetoothDevice.ACCESS_REJECTED) {
204 sendIntentToReceiver(intentName, false,
205 null, false ); // dummy value, no effect since previous param is null
208 Log.e(TAG, "Bad phonebookPermission: " + phonebookPermission);
211 } else if(mRequestType == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) {
213 int messagePermission = cachedDevice.getMessagePermissionChoice();
215 if (messagePermission == CachedBluetoothDevice.ACCESS_UNKNOWN) {
219 String intentName = BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY;
220 if (messagePermission == CachedBluetoothDevice.ACCESS_ALLOWED) {
221 sendIntentToReceiver(intentName, true, BluetoothDevice.EXTRA_ALWAYS_ALLOWED, true);
223 } else if (messagePermission == CachedBluetoothDevice.ACCESS_REJECTED) {
224 sendIntentToReceiver(intentName, false,
225 null, false); // dummy value, no effect since previous param is null
228 Log.e(TAG, "Bad messagePermission: " + messagePermission);
231 if(DEBUG) Log.d(TAG,"checkUserChoice(): returning " + processed);
235 private void sendIntentToReceiver(final String intentName, final boolean allowed,
236 final String extraName, final boolean extraValue) {
237 Intent intent = new Intent(intentName);
239 if (mReturnPackage != null && mReturnClass != null) {
240 intent.setClassName(mReturnPackage, mReturnClass);
243 intent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
244 allowed ? BluetoothDevice.CONNECTION_ACCESS_YES :
245 BluetoothDevice.CONNECTION_ACCESS_NO);
247 if (extraName != null) {
248 intent.putExtra(extraName, extraValue);
250 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
251 intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, mRequestType);
252 mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH_ADMIN);