• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getMapClientService()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 
setService(MapClientService instance)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 
connect(BluetoothDevice device)83     public synchronized boolean connect(BluetoothDevice device) {
84         Log.d(TAG, "MAP Mce connect " + device.toString());
85         return mMceStateMachine.connect(device);
86     }
87 
disconnect(BluetoothDevice device)88     public synchronized boolean disconnect(BluetoothDevice device) {
89         Log.d(TAG, "MAP Mce disconnect " + device.toString());
90         return mMceStateMachine.disconnect(device);
91     }
92 
getConnectedDevices()93     public List<BluetoothDevice> getConnectedDevices() {
94         return getDevicesMatchingConnectionStates(new int[]{BluetoothAdapter.STATE_CONNECTED});
95     }
96 
getDevicesMatchingConnectionStates(int[] states)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 
getConnectionState(BluetoothDevice device)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 
setPriority(BluetoothDevice device, int priority)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 
getPriority(BluetoothDevice device)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 
sendMessage(BluetoothDevice device, Uri[] contacts, String message, PendingIntent sentIntent, PendingIntent deliveredIntent)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
initBinder()149     protected IProfileServiceBinder initBinder() {
150         return new Binder(this);
151     }
152 
153     @Override
start()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
stop()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 
cleanup()183     public boolean cleanup() {
184         if (DBG) Log.d(TAG, "cleanup()");
185         return true;
186     }
187 
getUnreadMessages(BluetoothDevice device)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
dump(StringBuilder sb)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 
Binder(MapClientService service)211         Binder(MapClientService service) {
212             if (VDBG) Log.v(TAG, "Binder()");
213             mService = service;
214         }
215 
getService()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 
cleanup()230         public boolean cleanup() {
231             mService = null;
232             return true;
233         }
234 
isConnected(BluetoothDevice device)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 
connect(BluetoothDevice device)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 
disconnect(BluetoothDevice device)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 
getConnectedDevices()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 
getDevicesMatchingConnectionStates(int[] states)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 
getConnectionState(BluetoothDevice device)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 
setPriority(BluetoothDevice device, int priority)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 
getPriority(BluetoothDevice device)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 
sendMessage(BluetoothDevice device, Uri[] contacts, String message, PendingIntent sentIntent, PendingIntent deliveredIntent)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 
getUnreadMessages(BluetoothDevice device)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