Home | History | Annotate | Download | only in mapclient
      1 /*
      2  * Copyright (C) 2016 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.android.bluetooth.mapclient;
     18 
     19 import android.Manifest;
     20 import android.app.PendingIntent;
     21 import android.bluetooth.BluetoothAdapter;
     22 import android.bluetooth.BluetoothDevice;
     23 import android.bluetooth.BluetoothProfile;
     24 import android.bluetooth.IBluetoothMapClient;
     25 import android.net.Uri;
     26 import android.provider.Settings;
     27 import android.util.Log;
     28 
     29 import com.android.bluetooth.Utils;
     30 import com.android.bluetooth.btservice.ProfileService;
     31 
     32 import java.util.ArrayList;
     33 import java.util.Arrays;
     34 import java.util.List;
     35 import java.util.Set;
     36 
     37 public class MapClientService extends ProfileService {
     38     private static final String TAG = "MapClientService";
     39 
     40     static final boolean DBG = false;
     41     static final boolean VDBG = false;
     42 
     43     private static final int MAXIMUM_CONNECTED_DEVICES = 1;
     44 
     45     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
     46 
     47     MceStateMachine mMceStateMachine;
     48     private MnsService mMnsServer;
     49     private BluetoothAdapter mAdapter;
     50     private static MapClientService sMapClientService;
     51 
     52 
     53     public static synchronized MapClientService getMapClientService() {
     54         if (sMapClientService != null && sMapClientService.isAvailable()) {
     55             if (DBG) Log.d(TAG, "getMapClientService(): returning " + sMapClientService);
     56             return sMapClientService;
     57         }
     58         if (DBG) {
     59             if (sMapClientService == null) {
     60                 Log.d(TAG, "getMapClientService(): service is NULL");
     61             } else if (!(sMapClientService.isAvailable())) {
     62                 Log.d(TAG, "getMapClientService(): service is not available");
     63             }
     64         }
     65         return null;
     66     }
     67 
     68     private static synchronized void setService(MapClientService instance) {
     69         if (instance != null && instance.isAvailable()) {
     70             if (DBG) Log.d(TAG, "setMapMceService(): replacing old instance: " + sMapClientService);
     71             sMapClientService = instance;
     72         } else {
     73             if (DBG) {
     74                 if (sMapClientService == null) {
     75                     Log.d(TAG, "setA2dpService(): service not available");
     76                 } else if (!sMapClientService.isAvailable()) {
     77                     Log.d(TAG, "setA2dpService(): service is cleaning up");
     78                 }
     79             }
     80         }
     81     }
     82 
     83     public synchronized boolean connect(BluetoothDevice device) {
     84         Log.d(TAG, "MAP Mce connect " + device.toString());
     85         return mMceStateMachine.connect(device);
     86     }
     87 
     88     public synchronized boolean disconnect(BluetoothDevice device) {
     89         Log.d(TAG, "MAP Mce disconnect " + device.toString());
     90         return mMceStateMachine.disconnect(device);
     91     }
     92 
     93     public List<BluetoothDevice> getConnectedDevices() {
     94         return getDevicesMatchingConnectionStates(new int[]{BluetoothAdapter.STATE_CONNECTED});
     95     }
     96 
     97     public synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
     98         Log.d(TAG, "getDevicesMatchingConnectionStates" + Arrays.toString(states));
     99         List<BluetoothDevice> deviceList = new ArrayList<>();
    100         Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
    101         int connectionState;
    102         for (BluetoothDevice device : bondedDevices) {
    103             connectionState = getConnectionState(device);
    104             Log.d(TAG, "Device: " + device + "State: " + connectionState);
    105             for (int i = 0; i < states.length; i++) {
    106                 if (connectionState == states[i]) {
    107                     deviceList.add(device);
    108                 }
    109             }
    110         }
    111         Log.d(TAG, deviceList.toString());
    112         return deviceList;
    113     }
    114 
    115     public synchronized int getConnectionState(BluetoothDevice device) {
    116         if (mMceStateMachine != null && device.equals(mMceStateMachine.getDevice())) {
    117             return mMceStateMachine.getState();
    118         } else {
    119             return BluetoothProfile.STATE_DISCONNECTED;
    120         }
    121     }
    122 
    123     public boolean setPriority(BluetoothDevice device, int priority) {
    124         Settings.Global.putInt(getContentResolver(),
    125                 Settings.Global.getBluetoothMapClientPriorityKey(device.getAddress()),
    126                 priority);
    127         if (VDBG) Log.v(TAG, "Saved priority " + device + " = " + priority);
    128         return true;
    129     }
    130 
    131     public int getPriority(BluetoothDevice device) {
    132         int priority = Settings.Global.getInt(getContentResolver(),
    133                 Settings.Global.getBluetoothMapClientPriorityKey(device.getAddress()),
    134                 BluetoothProfile.PRIORITY_UNDEFINED);
    135         return priority;
    136     }
    137 
    138     public synchronized boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
    139             PendingIntent sentIntent, PendingIntent deliveredIntent) {
    140         if (mMceStateMachine != null && device.equals(mMceStateMachine.getDevice())) {
    141             return mMceStateMachine.sendMapMessage(contacts, message, sentIntent, deliveredIntent);
    142         } else {
    143             return false;
    144         }
    145 
    146     }
    147 
    148     @Override
    149     protected IProfileServiceBinder initBinder() {
    150         return new Binder(this);
    151     }
    152 
    153     @Override
    154     protected boolean start() {
    155         if (DBG) Log.d(TAG, "start()");
    156         setService(this);
    157 
    158         if (mMnsServer == null) {
    159             mMnsServer = new MnsService(this);
    160         }
    161         if (mMceStateMachine == null) {
    162             mMceStateMachine = new MceStateMachine(this);
    163         }
    164 
    165         mAdapter = BluetoothAdapter.getDefaultAdapter();
    166         mStartError = false;
    167         return !mStartError;
    168     }
    169 
    170     @Override
    171     protected synchronized boolean stop() {
    172         if (DBG) Log.d(TAG, "stop()");
    173         if (mMnsServer != null) {
    174             mMnsServer.stop();
    175         }
    176         if (mMceStateMachine.getState() == BluetoothAdapter.STATE_CONNECTED) {
    177             mMceStateMachine.disconnect(mMceStateMachine.getDevice());
    178         }
    179         mMceStateMachine.doQuit();
    180         return true;
    181     }
    182 
    183     public boolean cleanup() {
    184         if (DBG) Log.d(TAG, "cleanup()");
    185         return true;
    186     }
    187 
    188     public synchronized boolean getUnreadMessages(BluetoothDevice device) {
    189         if (mMceStateMachine != null && device.equals(mMceStateMachine.getDevice())) {
    190             return mMceStateMachine.getUnreadMessages();
    191         } else {
    192             return false;
    193         }
    194     }
    195 
    196     @Override
    197     public synchronized void dump(StringBuilder sb) {
    198         super.dump(sb);
    199         println(sb, "StateMachine: " + mMceStateMachine.toString());
    200     }
    201 
    202     //Binder object: Must be static class or memory leak may occur
    203     /**
    204      * This class implements the IClient interface - or actually it validates the
    205      * preconditions for calling the actual functionality in the MapClientService, and calls it.
    206      */
    207     private static class Binder extends IBluetoothMapClient.Stub
    208             implements IProfileServiceBinder {
    209         private MapClientService mService;
    210 
    211         Binder(MapClientService service) {
    212             if (VDBG) Log.v(TAG, "Binder()");
    213             mService = service;
    214         }
    215 
    216         private MapClientService getService() {
    217             if (!Utils.checkCaller()) {
    218                 Log.w(TAG, "MAP call not allowed for non-active user");
    219                 return null;
    220             }
    221 
    222             if (mService != null && mService.isAvailable()) {
    223                 mService.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
    224                         "Need BLUETOOTH permission");
    225                 return mService;
    226             }
    227             return null;
    228         }
    229 
    230         public boolean cleanup() {
    231             mService = null;
    232             return true;
    233         }
    234 
    235         public boolean isConnected(BluetoothDevice device) {
    236             if (VDBG) Log.v(TAG, "isConnected()");
    237             MapClientService service = getService();
    238             if (service == null) return false;
    239             return service.getConnectionState(device) == BluetoothProfile.STATE_CONNECTED;
    240         }
    241 
    242         public boolean connect(BluetoothDevice device) {
    243             if (VDBG) Log.v(TAG, "connect()");
    244             MapClientService service = getService();
    245             if (service == null) return false;
    246             return service.connect(device);
    247         }
    248 
    249         public boolean disconnect(BluetoothDevice device) {
    250             if (VDBG) Log.v(TAG, "disconnect()");
    251             MapClientService service = getService();
    252             if (service == null) return false;
    253             return service.disconnect(device);
    254         }
    255 
    256         public List<BluetoothDevice> getConnectedDevices() {
    257             if (VDBG) Log.v(TAG, "getConnectedDevices()");
    258             MapClientService service = getService();
    259             if (service == null) return new ArrayList<BluetoothDevice>(0);
    260             return service.getConnectedDevices();
    261         }
    262 
    263         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    264             if (VDBG) Log.v(TAG, "getDevicesMatchingConnectionStates()");
    265             MapClientService service = getService();
    266             if (service == null) return new ArrayList<BluetoothDevice>(0);
    267             return service.getDevicesMatchingConnectionStates(states);
    268         }
    269 
    270         public int getConnectionState(BluetoothDevice device) {
    271             if (VDBG) Log.v(TAG, "getConnectionState()");
    272             MapClientService service = getService();
    273             if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
    274             return service.getConnectionState(device);
    275         }
    276 
    277         public boolean setPriority(BluetoothDevice device, int priority) {
    278             MapClientService service = getService();
    279             if (service == null) return false;
    280             return service.setPriority(device, priority);
    281         }
    282 
    283         public int getPriority(BluetoothDevice device) {
    284             MapClientService service = getService();
    285             if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
    286             return service.getPriority(device);
    287         }
    288 
    289         public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
    290                 PendingIntent sentIntent, PendingIntent deliveredIntent) {
    291             MapClientService service = getService();
    292             if (service == null) return false;
    293             Log.d(TAG, "Checking Permission of sendMessage");
    294             mService.enforceCallingOrSelfPermission(Manifest.permission.SEND_SMS,
    295                     "Need SEND_SMS permission");
    296 
    297             return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent);
    298         }
    299 
    300         public boolean getUnreadMessages(BluetoothDevice device) {
    301             MapClientService service = getService();
    302             if (service == null) return false;
    303             mService.enforceCallingOrSelfPermission(Manifest.permission.READ_SMS,
    304                     "Need READ_SMS permission");
    305             return service.getUnreadMessages(device);
    306         }
    307     }
    308 }
    309