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.settingslib.bluetooth; 18 19 import android.bluetooth.BluetoothPbapClient; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothClass; 22 import android.bluetooth.BluetoothDevice; 23 import android.bluetooth.BluetoothProfile; 24 import android.bluetooth.BluetoothUuid; 25 import android.content.Context; 26 import android.os.ParcelUuid; 27 import android.util.Log; 28 29 import com.android.settingslib.R; 30 31 import java.util.ArrayList; 32 import java.util.Collection; 33 import java.util.List; 34 35 public final class PbapClientProfile implements LocalBluetoothProfile { 36 private static final String TAG = "PbapClientProfile"; 37 private static boolean V = false; 38 39 private BluetoothPbapClient mService; 40 private boolean mIsProfileReady; 41 42 private final LocalBluetoothAdapter mLocalAdapter; 43 private final CachedBluetoothDeviceManager mDeviceManager; 44 45 static final ParcelUuid[] SRC_UUIDS = { 46 BluetoothUuid.PBAP_PSE, 47 }; 48 49 static final String NAME = "PbapClient"; 50 private final LocalBluetoothProfileManager mProfileManager; 51 52 // Order of this profile in device profiles list 53 private static final int ORDINAL = 6; 54 55 // These callbacks run on the main thread. 56 private final class PbapClientServiceListener 57 implements BluetoothProfile.ServiceListener { 58 onServiceConnected(int profile, BluetoothProfile proxy)59 public void onServiceConnected(int profile, BluetoothProfile proxy) { 60 if (V) { 61 Log.d(TAG,"Bluetooth service connected"); 62 } 63 mService = (BluetoothPbapClient) proxy; 64 // We just bound to the service, so refresh the UI for any connected PBAP devices. 65 List<BluetoothDevice> deviceList = mService.getConnectedDevices(); 66 while (!deviceList.isEmpty()) { 67 BluetoothDevice nextDevice = deviceList.remove(0); 68 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); 69 // we may add a new device here, but generally this should not happen 70 if (device == null) { 71 Log.w(TAG, "PbapClientProfile found new device: " + nextDevice); 72 device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); 73 } 74 device.onProfileStateChanged(PbapClientProfile.this, BluetoothProfile.STATE_CONNECTED); 75 device.refresh(); 76 } 77 mIsProfileReady = true; 78 } 79 onServiceDisconnected(int profile)80 public void onServiceDisconnected(int profile) { 81 if (V) { 82 Log.d(TAG,"Bluetooth service disconnected"); 83 } 84 mIsProfileReady = false; 85 } 86 } 87 refreshProfiles()88 private void refreshProfiles() { 89 Collection<CachedBluetoothDevice> cachedDevices = mDeviceManager.getCachedDevicesCopy(); 90 for (CachedBluetoothDevice device : cachedDevices) { 91 device.onUuidChanged(); 92 } 93 } 94 pbapClientExists()95 public boolean pbapClientExists() { 96 return (mService != null); 97 } 98 isProfileReady()99 public boolean isProfileReady() { 100 return mIsProfileReady; 101 } 102 103 @Override getProfileId()104 public int getProfileId() { 105 return BluetoothProfile.PBAP_CLIENT; 106 } 107 PbapClientProfile(Context context, LocalBluetoothAdapter adapter, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)108 PbapClientProfile(Context context, LocalBluetoothAdapter adapter, 109 CachedBluetoothDeviceManager deviceManager, 110 LocalBluetoothProfileManager profileManager) { 111 mLocalAdapter = adapter; 112 mDeviceManager = deviceManager; 113 mProfileManager = profileManager; 114 mLocalAdapter.getProfileProxy(context, new PbapClientServiceListener(), 115 BluetoothProfile.PBAP_CLIENT); 116 } 117 isConnectable()118 public boolean isConnectable() { 119 return true; 120 } 121 isAutoConnectable()122 public boolean isAutoConnectable() { 123 return true; 124 } 125 getConnectedDevices()126 public List<BluetoothDevice> getConnectedDevices() { 127 if (mService == null) { 128 return new ArrayList<BluetoothDevice>(0); 129 } 130 return mService.getDevicesMatchingConnectionStates( 131 new int[] {BluetoothProfile.STATE_CONNECTED, 132 BluetoothProfile.STATE_CONNECTING, 133 BluetoothProfile.STATE_DISCONNECTING}); 134 } 135 connect(BluetoothDevice device)136 public boolean connect(BluetoothDevice device) { 137 if (V) { 138 Log.d(TAG,"PBAPClientProfile got connect request"); 139 } 140 if (mService == null) { 141 return false; 142 } 143 List<BluetoothDevice> srcs = getConnectedDevices(); 144 if (srcs != null) { 145 for (BluetoothDevice src : srcs) { 146 if (src.equals(device)) { 147 // Connect to same device, Ignore it 148 Log.d(TAG,"Ignoring Connect"); 149 return true; 150 } 151 } 152 } 153 Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress()); 154 155 return mService.connect(device); 156 } 157 disconnect(BluetoothDevice device)158 public boolean disconnect(BluetoothDevice device) { 159 if (V) { 160 Log.d(TAG,"PBAPClientProfile got disconnect request"); 161 } 162 if (mService == null) { 163 return false; 164 } 165 return mService.disconnect(device); 166 } 167 getConnectionStatus(BluetoothDevice device)168 public int getConnectionStatus(BluetoothDevice device) { 169 if (mService == null) { 170 return BluetoothProfile.STATE_DISCONNECTED; 171 } 172 return mService.getConnectionState(device); 173 } 174 isPreferred(BluetoothDevice device)175 public boolean isPreferred(BluetoothDevice device) { 176 if (mService == null) { 177 return false; 178 } 179 return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; 180 } 181 getPreferred(BluetoothDevice device)182 public int getPreferred(BluetoothDevice device) { 183 if (mService == null) { 184 return BluetoothProfile.PRIORITY_OFF; 185 } 186 return mService.getPriority(device); 187 } 188 setPreferred(BluetoothDevice device, boolean preferred)189 public void setPreferred(BluetoothDevice device, boolean preferred) { 190 if (mService == null) { 191 return; 192 } 193 if (preferred) { 194 if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { 195 mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 196 } 197 } else { 198 mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); 199 } 200 } 201 toString()202 public String toString() { 203 return NAME; 204 } 205 getOrdinal()206 public int getOrdinal() { 207 return ORDINAL; 208 } 209 getNameResource(BluetoothDevice device)210 public int getNameResource(BluetoothDevice device) { 211 // we need to have same string in UI as the server side. 212 return R.string.bluetooth_profile_pbap; 213 } 214 getSummaryResourceForDevice(BluetoothDevice device)215 public int getSummaryResourceForDevice(BluetoothDevice device) { 216 return R.string.bluetooth_profile_pbap_summary; 217 } 218 getDrawableResource(BluetoothClass btClass)219 public int getDrawableResource(BluetoothClass btClass) { 220 return R.drawable.ic_bt_cellphone; 221 } 222 finalize()223 protected void finalize() { 224 if (V) { 225 Log.d(TAG, "finalize()"); 226 } 227 if (mService != null) { 228 try { 229 BluetoothAdapter.getDefaultAdapter().closeProfileProxy( 230 BluetoothProfile.PBAP_CLIENT,mService); 231 mService = null; 232 } catch (Throwable t) { 233 Log.w(TAG, "Error cleaning up PBAP Client proxy", t); 234 } 235 } 236 } 237 } 238