/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.googlecode.android_scripting.facade.bluetooth; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import com.googlecode.android_scripting.Log; import com.googlecode.android_scripting.event.Event; import com.googlecode.android_scripting.facade.EventFacade; public class BluetoothPairingHelper extends BroadcastReceiver { private final EventFacade mEventFacade; private static final int DEFAULT_TIMEOUT_MS = 5000; private boolean mAutoConfirm = true; public BluetoothPairingHelper(EventFacade eventFacade) { super(); mEventFacade = eventFacade; Log.d("Pairing helper created."); } /** * Confirms bluetooth connection/bonding requests. */ @Override public void onReceive(Context c, Intent intent) { String action = intent.getAction(); Bundle result = new Bundle(); Log.d("Bluetooth pairing intent received: " + action); BluetoothDevice mDevice = intent.getParcelableExtra( BluetoothDevice.EXTRA_DEVICE); if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED); mDevice.setPhonebookAccessPermission( BluetoothDevice.ACCESS_ALLOWED); int type = intent.getIntExtra( BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR); Log.d("Processing Action Paring Request with type " + type); int pin = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, 0); String deviceAddress = mDevice.getAddress(); result.putInt("Pin", pin); result.putInt("PairingVariant", type); result.putString("DeviceAddress", deviceAddress); mEventFacade.postEvent("BluetoothActionPairingRequest", result.clone()); result.clear(); if (type == BluetoothDevice.PAIRING_VARIANT_CONSENT) { mDevice.setPairingConfirmation(true); Log.d("Connection auto-confirmed by consent"); // Abort the broadcast so Settings app doesn't get it. abortBroadcast(); } else if (type == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION) { if (mAutoConfirm) { mDevice.setPairingConfirmation(true); Log.d("Connection auto-confirmed"); } else { // Wait for confirmation Event userConfirmEvent = null; try { userConfirmEvent = mEventFacade.eventWaitFor( "BluetoothActionPairingRequestUserConfirm", true, DEFAULT_TIMEOUT_MS); } catch (InterruptedException e) { Log.d("Connection interrupted"); userConfirmEvent = null; } if (userConfirmEvent == null) { Log.d("Null response received from test server or timeout"); mDevice.setPairingConfirmation(false); } else { String userConfirmEventData = (String) userConfirmEvent.getData(); if (userConfirmEventData.equalsIgnoreCase("True")) { mDevice.setPairingConfirmation(true); Log.d("Connection confirmed"); } else { mDevice.setPairingConfirmation(false); Log.d("Connection rejected"); } } } // Abort the broadcast so Settings app doesn't get it. abortBroadcast(); } } else if (action.equals( BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) { int type = intent.getIntExtra( BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, BluetoothDevice.ERROR); Log.d("Processing Action Connection Access Request type " + type); if (type == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS || type == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS || type == BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION) { Intent newIntent = new Intent( BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); String mReturnPackage = intent.getStringExtra( BluetoothDevice.EXTRA_PACKAGE_NAME); String mReturnClass = intent.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME); int mRequestType = intent.getIntExtra( BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS); if (mReturnPackage != null && mReturnClass != null) { newIntent.setClassName(mReturnPackage, mReturnClass); } newIntent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, BluetoothDevice.CONNECTION_ACCESS_YES); newIntent.putExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, true); newIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); newIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, mRequestType); Log.d("Sending connection access acceptance intent."); abortBroadcast(); c.sendBroadcast(newIntent, android.Manifest.permission.BLUETOOTH_ADMIN); } } } /** * Set autoConfirm flag to Value. */ public synchronized void setAutoConfirm(boolean value) { mAutoConfirm = value; } }