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 PbapClientProfile(Context context, LocalBluetoothAdapter adapter, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)103 PbapClientProfile(Context context, LocalBluetoothAdapter adapter, 104 CachedBluetoothDeviceManager deviceManager, 105 LocalBluetoothProfileManager profileManager) { 106 mLocalAdapter = adapter; 107 mDeviceManager = deviceManager; 108 mProfileManager = profileManager; 109 mLocalAdapter.getProfileProxy(context, new PbapClientServiceListener(), 110 BluetoothProfile.PBAP_CLIENT); 111 } 112 isConnectable()113 public boolean isConnectable() { 114 return true; 115 } 116 isAutoConnectable()117 public boolean isAutoConnectable() { 118 return true; 119 } 120 getConnectedDevices()121 public List<BluetoothDevice> getConnectedDevices() { 122 if (mService == null) { 123 return new ArrayList<BluetoothDevice>(0); 124 } 125 return mService.getDevicesMatchingConnectionStates( 126 new int[] {BluetoothProfile.STATE_CONNECTED, 127 BluetoothProfile.STATE_CONNECTING, 128 BluetoothProfile.STATE_DISCONNECTING}); 129 } 130 connect(BluetoothDevice device)131 public boolean connect(BluetoothDevice device) { 132 if (V) { 133 Log.d(TAG,"PBAPClientProfile got connect request"); 134 } 135 if (mService == null) { 136 return false; 137 } 138 List<BluetoothDevice> srcs = getConnectedDevices(); 139 if (srcs != null) { 140 for (BluetoothDevice src : srcs) { 141 if (src.equals(device)) { 142 // Connect to same device, Ignore it 143 Log.d(TAG,"Ignoring Connect"); 144 return true; 145 } 146 } 147 } 148 Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress()); 149 150 return mService.connect(device); 151 } 152 disconnect(BluetoothDevice device)153 public boolean disconnect(BluetoothDevice device) { 154 if (V) { 155 Log.d(TAG,"PBAPClientProfile got disconnect request"); 156 } 157 if (mService == null) { 158 return false; 159 } 160 return mService.disconnect(device); 161 } 162 getConnectionStatus(BluetoothDevice device)163 public int getConnectionStatus(BluetoothDevice device) { 164 if (mService == null) { 165 return BluetoothProfile.STATE_DISCONNECTED; 166 } 167 return mService.getConnectionState(device); 168 } 169 isPreferred(BluetoothDevice device)170 public boolean isPreferred(BluetoothDevice device) { 171 if (mService == null) { 172 return false; 173 } 174 return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; 175 } 176 getPreferred(BluetoothDevice device)177 public int getPreferred(BluetoothDevice device) { 178 if (mService == null) { 179 return BluetoothProfile.PRIORITY_OFF; 180 } 181 return mService.getPriority(device); 182 } 183 setPreferred(BluetoothDevice device, boolean preferred)184 public void setPreferred(BluetoothDevice device, boolean preferred) { 185 if (mService == null) { 186 return; 187 } 188 if (preferred) { 189 if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { 190 mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 191 } 192 } else { 193 mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); 194 } 195 } 196 toString()197 public String toString() { 198 return NAME; 199 } 200 getOrdinal()201 public int getOrdinal() { 202 return ORDINAL; 203 } 204 getNameResource(BluetoothDevice device)205 public int getNameResource(BluetoothDevice device) { 206 // we need to have same string in UI as the server side. 207 return R.string.bluetooth_profile_pbap; 208 } 209 getSummaryResourceForDevice(BluetoothDevice device)210 public int getSummaryResourceForDevice(BluetoothDevice device) { 211 return R.string.bluetooth_profile_pbap_summary; 212 } 213 getDrawableResource(BluetoothClass btClass)214 public int getDrawableResource(BluetoothClass btClass) { 215 return R.drawable.ic_bt_cellphone; 216 } 217 finalize()218 protected void finalize() { 219 if (V) { 220 Log.d(TAG, "finalize()"); 221 } 222 if (mService != null) { 223 try { 224 BluetoothAdapter.getDefaultAdapter().closeProfileProxy( 225 BluetoothProfile.PBAP_CLIENT,mService); 226 mService = null; 227 } catch (Throwable t) { 228 Log.w(TAG, "Error cleaning up PBAP Client proxy", t); 229 } 230 } 231 } 232 } 233