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