1/*
2 * Copyright (C) 2008 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
17package com.android.settings.bluetooth;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.bluetooth.BluetoothDevice;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.res.Resources;
27import android.os.PowerManager;
28import android.text.TextUtils;
29
30import com.android.settings.R;
31
32/**
33 * BluetoothPairingRequest is a receiver for any Bluetooth pairing request. It
34 * checks if the Bluetooth Settings is currently visible and brings up the PIN, the passkey or a
35 * confirmation entry dialog. Otherwise it puts a Notification in the status bar, which can
36 * be clicked to bring up the Pairing entry dialog.
37 */
38public final class BluetoothPairingRequest extends BroadcastReceiver {
39
40    private static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth;
41
42    @Override
43    public void onReceive(Context context, Intent intent) {
44        String action = intent.getAction();
45        if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
46            // convert broadcast intent into activity intent (same action string)
47            BluetoothDevice device =
48                    intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
49            int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
50                    BluetoothDevice.ERROR);
51            Intent pairingIntent = new Intent();
52            pairingIntent.setClass(context, BluetoothPairingDialog.class);
53            pairingIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
54            pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, type);
55            if (type == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION ||
56                    type == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY ||
57                    type == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) {
58                int pairingKey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY,
59                        BluetoothDevice.ERROR);
60                pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pairingKey);
61            }
62            pairingIntent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
63            pairingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
64
65            PowerManager powerManager =
66                    (PowerManager)context.getSystemService(Context.POWER_SERVICE);
67            String deviceAddress = device != null ? device.getAddress() : null;
68            String deviceName = device != null ? device.getName() : null;
69            boolean shouldShowDialog= LocalBluetoothPreferences.shouldShowDialogInForeground(
70                        context, deviceAddress, deviceName);
71            if (powerManager.isInteractive() && shouldShowDialog) {
72                // Since the screen is on and the BT-related activity is in the foreground,
73                // just open the dialog
74                context.startActivity(pairingIntent);
75            } else {
76                // Put up a notification that leads to the dialog
77                Resources res = context.getResources();
78                Notification.Builder builder = new Notification.Builder(context)
79                        .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
80                        .setTicker(res.getString(R.string.bluetooth_notif_ticker));
81
82                PendingIntent pending = PendingIntent.getActivity(context, 0,
83                        pairingIntent, PendingIntent.FLAG_ONE_SHOT);
84
85                String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
86                if (TextUtils.isEmpty(name)) {
87                    name = device != null ? device.getAliasName() :
88                            context.getString(android.R.string.unknownName);
89                }
90
91                builder.setContentTitle(res.getString(R.string.bluetooth_notif_title))
92                        .setContentText(res.getString(R.string.bluetooth_notif_message, name))
93                        .setContentIntent(pending)
94                        .setAutoCancel(true)
95                        .setDefaults(Notification.DEFAULT_SOUND)
96                        .setColor(context.getColor(
97                                com.android.internal.R.color.system_notification_accent_color));
98
99                NotificationManager manager = (NotificationManager)
100                        context.getSystemService(Context.NOTIFICATION_SERVICE);
101                manager.notify(NOTIFICATION_ID, builder.getNotification());
102            }
103
104        } else if (action.equals(BluetoothDevice.ACTION_PAIRING_CANCEL)) {
105
106            // Remove the notification
107            NotificationManager manager = (NotificationManager) context
108                    .getSystemService(Context.NOTIFICATION_SERVICE);
109            manager.cancel(NOTIFICATION_ID);
110
111        } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
112            int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
113                    BluetoothDevice.ERROR);
114            int oldState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE,
115                    BluetoothDevice.ERROR);
116            if((oldState == BluetoothDevice.BOND_BONDING) &&
117                    (bondState == BluetoothDevice.BOND_NONE)) {
118                // Remove the notification
119                NotificationManager manager = (NotificationManager) context
120                    .getSystemService(Context.NOTIFICATION_SERVICE);
121                manager.cancel(NOTIFICATION_ID);
122            }
123        }
124    }
125}
126