1 /* 2 * Copyright (C) 2017 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.googlecode.android_scripting.facade.bluetooth; 18 19 import android.bluetooth.BluetoothDevice; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.os.Bundle; 24 25 import com.googlecode.android_scripting.Log; 26 import com.googlecode.android_scripting.event.Event; 27 import com.googlecode.android_scripting.facade.EventFacade; 28 29 public class BluetoothPairingHelper extends BroadcastReceiver { 30 private final EventFacade mEventFacade; 31 private static final int DEFAULT_TIMEOUT_MS = 5000; 32 private boolean mAutoConfirm = true; 33 34 public BluetoothPairingHelper(EventFacade eventFacade) { 35 super(); 36 mEventFacade = eventFacade; 37 Log.d("Pairing helper created."); 38 } 39 40 /** 41 * Confirms bluetooth connection/bonding requests. 42 */ 43 @Override 44 public void onReceive(Context c, Intent intent) { 45 String action = intent.getAction(); 46 Bundle result = new Bundle(); 47 Log.d("Bluetooth pairing intent received: " + action); 48 BluetoothDevice mDevice = intent.getParcelableExtra( 49 BluetoothDevice.EXTRA_DEVICE); 50 if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { 51 mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED); 52 mDevice.setPhonebookAccessPermission( 53 BluetoothDevice.ACCESS_ALLOWED); 54 int type = intent.getIntExtra( 55 BluetoothDevice.EXTRA_PAIRING_VARIANT, 56 BluetoothDevice.ERROR); 57 Log.d("Processing Action Paring Request with type " + type); 58 int pin = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, 0); 59 String deviceAddress = mDevice.getAddress(); 60 result.putInt("Pin", pin); 61 result.putInt("PairingVariant", type); 62 result.putString("DeviceAddress", deviceAddress); 63 mEventFacade.postEvent("BluetoothActionPairingRequest", 64 result.clone()); 65 result.clear(); 66 if (type == BluetoothDevice.PAIRING_VARIANT_CONSENT) { 67 mDevice.setPairingConfirmation(true); 68 Log.d("Connection auto-confirmed by consent"); 69 // Abort the broadcast so Settings app doesn't get it. 70 abortBroadcast(); 71 } else if (type 72 == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION) { 73 if (mAutoConfirm) { 74 mDevice.setPairingConfirmation(true); 75 Log.d("Connection auto-confirmed"); 76 } else { 77 // Wait for confirmation 78 Event userConfirmEvent = null; 79 try { 80 userConfirmEvent = mEventFacade.eventWaitFor( 81 "BluetoothActionPairingRequestUserConfirm", 82 true, DEFAULT_TIMEOUT_MS); 83 } catch (InterruptedException e) { 84 Log.d("Connection interrupted"); 85 userConfirmEvent = null; 86 } 87 if (userConfirmEvent == null) { 88 Log.d("Null response received from test server or timeout"); 89 mDevice.setPairingConfirmation(false); 90 } else { 91 String userConfirmEventData = 92 (String) userConfirmEvent.getData(); 93 if (userConfirmEventData.equalsIgnoreCase("True")) { 94 mDevice.setPairingConfirmation(true); 95 Log.d("Connection confirmed"); 96 } else { 97 mDevice.setPairingConfirmation(false); 98 Log.d("Connection rejected"); 99 } 100 } 101 } 102 // Abort the broadcast so Settings app doesn't get it. 103 abortBroadcast(); 104 } 105 } else if (action.equals( 106 BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) { 107 int type = intent.getIntExtra( 108 BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 109 BluetoothDevice.ERROR); 110 Log.d("Processing Action Connection Access Request type " + type); 111 if (type == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS 112 || type == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS 113 || type 114 == BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION) { 115 Intent newIntent = 116 new Intent( 117 BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); 118 String mReturnPackage = 119 intent.getStringExtra( 120 BluetoothDevice.EXTRA_PACKAGE_NAME); 121 String mReturnClass = 122 intent.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME); 123 int mRequestType = 124 intent.getIntExtra( 125 BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 126 BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS); 127 if (mReturnPackage != null && mReturnClass != null) { 128 newIntent.setClassName(mReturnPackage, mReturnClass); 129 } 130 newIntent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, 131 BluetoothDevice.CONNECTION_ACCESS_YES); 132 newIntent.putExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, true); 133 newIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); 134 newIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 135 mRequestType); 136 Log.d("Sending connection access acceptance intent."); 137 abortBroadcast(); 138 c.sendBroadcast(newIntent, 139 android.Manifest.permission.BLUETOOTH_ADMIN); 140 } 141 } 142 } 143 144 /** 145 * Set autoConfirm flag to Value. 146 */ 147 public synchronized void setAutoConfirm(boolean value) { 148 mAutoConfirm = value; 149 } 150 } 151