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(
     76                 BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
     77         mDeliveryIntent = new Intent(
     78                 BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
     79         IntentFilter intentFilter = new IntentFilter();
     80         intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_RECEIVED);
     81         intentFilter.addAction(
     82                 BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
     83         intentFilter.addAction(
     84                 BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
     85         mService.registerReceiver(mNotificationReceiver, intentFilter);
     86         Log.d("notification receiver registered");
     87     }
     88 
     89     class MapServiceListener implements BluetoothProfile.ServiceListener {
     90         @Override
     91         public void onServiceConnected(int profile, BluetoothProfile proxy) {
     92             sMapProfile = (BluetoothMapClient) proxy;
     93             sIsMapReady = true;
     94         }
     95 
     96         @Override
     97         public void onServiceDisconnected(int profile) {
     98             sIsMapReady = false;
     99         }
    100     }
    101 
    102     public Boolean mapClientConnect(BluetoothDevice device) {
    103         if (sMapProfile == null) return false;
    104         return sMapProfile.connect(device);
    105     }
    106 
    107     public Boolean mapClientDisconnect(BluetoothDevice device) {
    108         if (sMapProfile == null) return false;
    109         return sMapProfile.disconnect(device);
    110     }
    111 
    112     @Rpc(description = "Connect to an MAP MSE device.")
    113     public Boolean bluetoothMapClientConnect(
    114             @RpcParameter(name = "device",
    115                     description = "Name or MAC address of a bluetooth "
    116                     + "device.")
    117                     String device)
    118             throws Exception {
    119         if (sMapProfile == null) return false;
    120         BluetoothDevice mDevice = BluetoothFacade.getDevice(
    121                 mBluetoothAdapter.getBondedDevices(), device);
    122         Log.d("Connecting to device " + mDevice.getAliasName());
    123         return sMapProfile.connect(mDevice);
    124     }
    125 
    126     @Rpc(description = "Send a (text) message via bluetooth.")
    127     public Boolean mapSendMessage(
    128             @RpcParameter(name = "deviceID",
    129                     description = "Name or MAC address of a device.")
    130                     String deviceID,
    131             @RpcParameter(name = "phoneNumbers",
    132                     description = "Phone number of contact.")
    133                     String[] phoneNumbers,
    134             @RpcParameter(name = "message",
    135                     description = "Message to send.") String message) {
    136         try {
    137             BluetoothDevice device =
    138                     BluetoothFacade.getDevice(
    139                             sMapProfile.getConnectedDevices(), deviceID);
    140             mSentIntent = PendingIntent.getBroadcast(mService, 0, mSendIntent,
    141                     PendingIntent.FLAG_ONE_SHOT);
    142             mDeliveredIntent = PendingIntent.getBroadcast(
    143                     mService, 0, mDeliveryIntent,
    144                     PendingIntent.FLAG_ONE_SHOT);
    145             Uri[] contacts = new Uri[phoneNumbers.length];
    146             for (int i = 0; i < phoneNumbers.length; i++) {
    147                 Log.d("PhoneNumber count: " + phoneNumbers.length + " = "
    148                         + phoneNumbers[i]);
    149                 contacts[i] = Uri.parse(phoneNumbers[i]);
    150             }
    151             return sMapProfile.sendMessage(device, contacts, message, mSentIntent,
    152                     mDeliveredIntent);
    153         } catch (Exception e) {
    154             Log.d("Error sending message, no such device " + e.toString());
    155         }
    156         return false;
    157     }
    158 
    159     public Boolean mapDisconnect(BluetoothDevice device) {
    160         if (sMapProfile.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
    161             sMapProfile.setPriority(device, BluetoothProfile.PRIORITY_ON);
    162         }
    163         return sMapProfile.disconnect(device);
    164     }
    165 
    166     @Rpc(description = "Is Map profile ready.")
    167     public Boolean bluetoothMapClientIsReady() {
    168         return sIsMapReady;
    169     }
    170 
    171     @Rpc(description = "Disconnect an MAP device.")
    172     public Boolean bluetoothMapClientDisconnect(
    173             @RpcParameter(name = "deviceID",
    174                     description = "Name or MAC address of a device.")
    175                     String deviceID)
    176             throws Exception {
    177         if (sMapProfile == null) return false;
    178         List<BluetoothDevice> connectedMapDevices =
    179                 sMapProfile.getConnectedDevices();
    180         Log.d("Connected map devices: " + connectedMapDevices);
    181         BluetoothDevice mDevice = BluetoothFacade.getDevice(
    182                 connectedMapDevices, deviceID);
    183         if (!connectedMapDevices.isEmpty()
    184                 && connectedMapDevices.get(0).equals(mDevice)) {
    185             if (sMapProfile.getPriority(mDevice) > BluetoothProfile.PRIORITY_ON) {
    186                 sMapProfile.setPriority(mDevice, BluetoothProfile.PRIORITY_ON);
    187             }
    188             return sMapProfile.disconnect(mDevice);
    189         } else {
    190             return false;
    191         }
    192     }
    193 
    194     @Rpc(description = "Get all the devices connected through MAP.")
    195     public List<BluetoothDevice> bluetoothMapClientGetConnectedDevices() {
    196         while (!sIsMapReady) ;
    197         return sMapProfile.getDevicesMatchingConnectionStates(
    198                 new int[]{BluetoothProfile.STATE_CONNECTED,
    199                         BluetoothProfile.STATE_CONNECTING,
    200                         BluetoothProfile.STATE_DISCONNECTING});
    201     }
    202 
    203     @Override
    204     public void shutdown() {
    205         mService.unregisterReceiver(mNotificationReceiver);
    206     }
    207 
    208     public class NotificationReceiver extends BroadcastReceiver {
    209         @Override
    210         public void onReceive(Context context, Intent intent) {
    211             Log.d("OnReceive" + intent);
    212             String action = intent.getAction();
    213             if (action.equals(BluetoothMapClient.ACTION_MESSAGE_RECEIVED)) {
    214                 mEventFacade.postEvent(MAP_EVENT,
    215                         intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
    216             } else if (action.equals(
    217                     BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY)) {
    218                 mEventFacade.postEvent(MAP_SMS_SENT_SUCCESS,
    219                         intent.getStringExtra(
    220                             android.content.Intent.EXTRA_TEXT));
    221             } else if (action.equals(
    222                     BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY)) {
    223                 mEventFacade.postEvent(MAP_SMS_DELIVER_SUCCESS,
    224                         intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
    225             }
    226         }
    227     }
    228 }
    229