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.app.PendingIntent;
     20 import android.app.Service;
     21 import android.bluetooth.BluetoothAdapter;
     22 import android.bluetooth.BluetoothDevice;
     23 import android.bluetooth.BluetoothMapClient;
     24 import android.bluetooth.BluetoothProfile;
     25 import android.bluetooth.BluetoothUuid;
     26 import android.content.BroadcastReceiver;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.content.IntentFilter;
     30 import android.net.Uri;
     31 import android.os.ParcelUuid;
     32 
     33 import com.googlecode.android_scripting.Log;
     34 import com.googlecode.android_scripting.facade.EventFacade;
     35 import com.googlecode.android_scripting.facade.FacadeManager;
     36 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
     37 import com.googlecode.android_scripting.rpc.Rpc;
     38 import com.googlecode.android_scripting.rpc.RpcParameter;
     39 
     40 import java.util.List;
     41 
     42 public class BluetoothMapClientFacade extends RpcReceiver {
     43     static final ParcelUuid[] MAP_UUIDS = {
     44             BluetoothUuid.MAP,
     45             BluetoothUuid.MNS,
     46             BluetoothUuid.MAS,
     47     };
     48     public static final String MAP_EVENT = "MapMessageReceived";
     49     public static final String MAP_SMS_SENT_SUCCESS = "SmsSentSuccess";
     50     public static final String MAP_SMS_DELIVER_SUCCESS = "SmsDeliverSuccess";
     51 
     52     private final Service mService;
     53     private final BluetoothAdapter mBluetoothAdapter;
     54     private final EventFacade mEventFacade;
     55     private final NotificationReceiver mNotificationReceiver;
     56 
     57     private Intent mSendIntent;
     58     private Intent mDeliveryIntent;
     59     private PendingIntent mSentIntent;
     60     private PendingIntent mDeliveredIntent;
     61 
     62     private static boolean sIsMapReady = false;
     63     private static BluetoothMapClient sMapProfile = null;
     64 
     65     public BluetoothMapClientFacade(FacadeManager manager) {
     66         super(manager);
     67         Log.d("Creating BluetoothMapClientFacade");
     68         mService = manager.getService();
     69         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
     70         mBluetoothAdapter.getProfileProxy(mService, new MapServiceListener(),
     71                 BluetoothProfile.MAP_CLIENT);
     72         mEventFacade = manager.getReceiver(EventFacade.class);
     73 
     74         mNotificationReceiver = new NotificationReceiver();
     75         mSendIntent = new Intent(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
     76         mDeliveryIntent = new Intent(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
     77         IntentFilter intentFilter = new IntentFilter();
     78         intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_RECEIVED);
     79         intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
     80         intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
     81         mService.registerReceiver(mNotificationReceiver, intentFilter);
     82         Log.d("notification receiver registered");
     83     }
     84 
     85     class MapServiceListener implements BluetoothProfile.ServiceListener {
     86         @Override
     87         public void onServiceConnected(int profile, BluetoothProfile proxy) {
     88             sMapProfile = (BluetoothMapClient) proxy;
     89             sIsMapReady = true;
     90         }
     91 
     92         @Override
     93         public void onServiceDisconnected(int profile) {
     94             sIsMapReady = false;
     95         }
     96     }
     97 
     98     public Boolean mapClientConnect(BluetoothDevice device) {
     99         if (sMapProfile == null) return false;
    100         return sMapProfile.connect(device);
    101     }
    102 
    103     public Boolean mapClientDisconnect(BluetoothDevice device) {
    104         if (sMapProfile == null) return false;
    105         return sMapProfile.disconnect(device);
    106     }
    107 
    108     @Rpc(description = "Connect to an MAP MSE device.")
    109     public Boolean bluetoothMapClientConnect(
    110             @RpcParameter(name = "device", description = "Name or MAC address of a bluetooth "
    111                     + "device.")
    112                     String device)
    113             throws Exception {
    114         if (sMapProfile == null) return false;
    115         BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
    116                 device);
    117         Log.d("Connecting to device " + mDevice.getAliasName());
    118         return sMapProfile.connect(mDevice);
    119     }
    120 
    121     @Rpc(description = "Send a (text) message via bluetooth.")
    122     public Boolean mapSendMessage(
    123             @RpcParameter(name = "deviceID", description = "Name or MAC address of a device.")
    124                     String deviceID,
    125             @RpcParameter(name = "phoneNumbers", description = "Phone number of contact.")
    126                     String[] phoneNumbers,
    127             @RpcParameter(name = "message", description = "Message to send.") String message) {
    128         try {
    129             BluetoothDevice device =
    130                     BluetoothFacade.getDevice(sMapProfile.getConnectedDevices(), deviceID);
    131             mSentIntent = PendingIntent.getBroadcast(mService, 0, mSendIntent,
    132                     PendingIntent.FLAG_ONE_SHOT);
    133             mDeliveredIntent = PendingIntent.getBroadcast(mService, 0, mDeliveryIntent,
    134                     PendingIntent.FLAG_ONE_SHOT);
    135             Uri[] contacts = new Uri[phoneNumbers.length];
    136             for (int i = 0; i < phoneNumbers.length; i++) {
    137                 Log.d("PhoneNumber count: " + phoneNumbers.length + " = " + phoneNumbers[i]);
    138                 contacts[i] = Uri.parse(phoneNumbers[i]);
    139             }
    140             return sMapProfile.sendMessage(device, contacts, message, mSentIntent,
    141                     mDeliveredIntent);
    142         } catch (Exception e) {
    143             Log.d("Error sending message, no such device " + e.toString());
    144         }
    145         return false;
    146     }
    147 
    148     public Boolean mapDisconnect(BluetoothDevice device) {
    149         if (sMapProfile.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
    150             sMapProfile.setPriority(device, BluetoothProfile.PRIORITY_ON);
    151         }
    152         return sMapProfile.disconnect(device);
    153     }
    154 
    155     @Rpc(description = "Is Map profile ready.")
    156     public Boolean bluetoothMapClientIsReady() {
    157         return sIsMapReady;
    158     }
    159 
    160     @Rpc(description = "Disconnect an MAP device.")
    161     public Boolean bluetoothMapClientDisconnect(
    162             @RpcParameter(name = "deviceID", description = "Name or MAC address of a device.")
    163                     String deviceID)
    164             throws Exception {
    165         if (sMapProfile == null) return false;
    166         List<BluetoothDevice> connectedMapDevices = sMapProfile.getConnectedDevices();
    167         Log.d("Connected map devices: " + connectedMapDevices);
    168         BluetoothDevice mDevice = BluetoothFacade.getDevice(connectedMapDevices, deviceID);
    169         if (!connectedMapDevices.isEmpty() && connectedMapDevices.get(0).equals(mDevice)) {
    170             if (sMapProfile.getPriority(mDevice) > BluetoothProfile.PRIORITY_ON) {
    171                 sMapProfile.setPriority(mDevice, BluetoothProfile.PRIORITY_ON);
    172             }
    173             return sMapProfile.disconnect(mDevice);
    174         } else {
    175             return false;
    176         }
    177     }
    178 
    179     @Rpc(description = "Get all the devices connected through MAP.")
    180     public List<BluetoothDevice> bluetoothMapClientGetConnectedDevices() {
    181         while (!sIsMapReady) ;
    182         return sMapProfile.getDevicesMatchingConnectionStates(
    183                 new int[]{BluetoothProfile.STATE_CONNECTED,
    184                         BluetoothProfile.STATE_CONNECTING,
    185                         BluetoothProfile.STATE_DISCONNECTING});
    186     }
    187 
    188     @Override
    189     public void shutdown() {
    190         mService.unregisterReceiver(mNotificationReceiver);
    191     }
    192 
    193     public class NotificationReceiver extends BroadcastReceiver {
    194         @Override
    195         public void onReceive(Context context, Intent intent) {
    196             Log.d("OnReceive" + intent);
    197             String action = intent.getAction();
    198             if (action.equals(BluetoothMapClient.ACTION_MESSAGE_RECEIVED)) {
    199                 mEventFacade.postEvent(MAP_EVENT,
    200                         intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
    201             } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY)) {
    202                 mEventFacade.postEvent(MAP_SMS_SENT_SUCCESS,
    203                         intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
    204             } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY)) {
    205                 mEventFacade.postEvent(MAP_SMS_DELIVER_SUCCESS,
    206                         intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
    207             }
    208         }
    209     }
    210 }
    211