1 /*
2  * Copyright (C) 2012 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.settingslib.bluetooth;
18 
19 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
20 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
21 
22 import android.bluetooth.BluetoothAdapter;
23 import android.bluetooth.BluetoothClass;
24 import android.bluetooth.BluetoothDevice;
25 import android.bluetooth.BluetoothMap;
26 import android.bluetooth.BluetoothProfile;
27 import android.bluetooth.BluetoothUuid;
28 import android.content.Context;
29 import android.os.ParcelUuid;
30 import android.util.Log;
31 
32 import com.android.settingslib.R;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 
37 /**
38  * MapProfile handles the Bluetooth MAP MSE role
39  */
40 public class MapProfile implements LocalBluetoothProfile {
41     private static final String TAG = "MapProfile";
42 
43     private BluetoothMap mService;
44     private boolean mIsProfileReady;
45 
46     private final CachedBluetoothDeviceManager mDeviceManager;
47     private final LocalBluetoothProfileManager mProfileManager;
48 
49     static final ParcelUuid[] UUIDS = {
50         BluetoothUuid.MAP,
51         BluetoothUuid.MNS,
52         BluetoothUuid.MAS,
53     };
54 
55     static final String NAME = "MAP";
56 
57     // Order of this profile in device profiles list
58 
59     // These callbacks run on the main thread.
60     private final class MapServiceListener
61             implements BluetoothProfile.ServiceListener {
62 
onServiceConnected(int profile, BluetoothProfile proxy)63         public void onServiceConnected(int profile, BluetoothProfile proxy) {
64             mService = (BluetoothMap) proxy;
65             // We just bound to the service, so refresh the UI for any connected MAP devices.
66             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
67             while (!deviceList.isEmpty()) {
68                 BluetoothDevice nextDevice = deviceList.remove(0);
69                 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
70                 // we may add a new device here, but generally this should not happen
71                 if (device == null) {
72                     Log.w(TAG, "MapProfile found new device: " + nextDevice);
73                     device = mDeviceManager.addDevice(nextDevice);
74                 }
75                 device.onProfileStateChanged(MapProfile.this,
76                         BluetoothProfile.STATE_CONNECTED);
77                 device.refresh();
78             }
79 
80             mProfileManager.callServiceConnectedListeners();
81             mIsProfileReady=true;
82         }
83 
onServiceDisconnected(int profile)84         public void onServiceDisconnected(int profile) {
85             mProfileManager.callServiceDisconnectedListeners();
86             mIsProfileReady=false;
87         }
88     }
89 
isProfileReady()90     public boolean isProfileReady() {
91         Log.d(TAG, "isProfileReady(): " + mIsProfileReady);
92         return mIsProfileReady;
93     }
94 
95     @Override
getProfileId()96     public int getProfileId() {
97         return BluetoothProfile.MAP;
98     }
99 
MapProfile(Context context, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)100     MapProfile(Context context, CachedBluetoothDeviceManager deviceManager,
101             LocalBluetoothProfileManager profileManager) {
102         mDeviceManager = deviceManager;
103         mProfileManager = profileManager;
104         BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new MapServiceListener(),
105                 BluetoothProfile.MAP);
106     }
107 
accessProfileEnabled()108     public boolean accessProfileEnabled() {
109         return true;
110     }
111 
isAutoConnectable()112     public boolean isAutoConnectable() {
113         return true;
114     }
115 
getConnectionStatus(BluetoothDevice device)116     public int getConnectionStatus(BluetoothDevice device) {
117         if (mService == null) {
118             return BluetoothProfile.STATE_DISCONNECTED;
119         }
120         return mService.getConnectionState(device);
121     }
122 
123     @Override
isEnabled(BluetoothDevice device)124     public boolean isEnabled(BluetoothDevice device) {
125         if (mService == null) {
126             return false;
127         }
128         return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
129     }
130 
131     @Override
getConnectionPolicy(BluetoothDevice device)132     public int getConnectionPolicy(BluetoothDevice device) {
133         if (mService == null) {
134             return CONNECTION_POLICY_FORBIDDEN;
135         }
136         return mService.getConnectionPolicy(device);
137     }
138 
139     @Override
setEnabled(BluetoothDevice device, boolean enabled)140     public boolean setEnabled(BluetoothDevice device, boolean enabled) {
141         boolean isSuccessful = false;
142         if (mService == null) {
143             return false;
144         }
145         if (enabled) {
146             if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
147                 isSuccessful = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
148             }
149         } else {
150             isSuccessful = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
151         }
152 
153         return isSuccessful;
154     }
155 
getConnectedDevices()156     public List<BluetoothDevice> getConnectedDevices() {
157         if (mService == null) {
158             return new ArrayList<BluetoothDevice>(0);
159         }
160         return mService.getDevicesMatchingConnectionStates(
161               new int[] {BluetoothProfile.STATE_CONNECTED,
162                          BluetoothProfile.STATE_CONNECTING,
163                          BluetoothProfile.STATE_DISCONNECTING});
164     }
165 
toString()166     public String toString() {
167         return NAME;
168     }
169 
getOrdinal()170     public int getOrdinal() {
171         return BluetoothProfile.MAP;
172     }
173 
getNameResource(BluetoothDevice device)174     public int getNameResource(BluetoothDevice device) {
175         return R.string.bluetooth_profile_map;
176     }
177 
getSummaryResourceForDevice(BluetoothDevice device)178     public int getSummaryResourceForDevice(BluetoothDevice device) {
179         int state = getConnectionStatus(device);
180         switch (state) {
181             case BluetoothProfile.STATE_DISCONNECTED:
182                 return R.string.bluetooth_map_profile_summary_use_for;
183 
184             case BluetoothProfile.STATE_CONNECTED:
185                 return R.string.bluetooth_map_profile_summary_connected;
186 
187             default:
188                 return BluetoothUtils.getConnectionStateSummary(state);
189         }
190     }
191 
getDrawableResource(BluetoothClass btClass)192     public int getDrawableResource(BluetoothClass btClass) {
193         return com.android.internal.R.drawable.ic_phone;
194     }
195 
finalize()196     protected void finalize() {
197         Log.d(TAG, "finalize()");
198         if (mService != null) {
199             try {
200                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP,
201                                                                        mService);
202                 mService = null;
203             }catch (Throwable t) {
204                 Log.w(TAG, "Error cleaning up MAP proxy", t);
205             }
206         }
207     }
208 }
209