Home | History | Annotate | Download | only in bluetooth
      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