Home | History | Annotate | Download | only in bluetooth
      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.BluetoothAdapter;
     20 import android.bluetooth.BluetoothClass;
     21 import android.bluetooth.BluetoothDevice;
     22 import android.bluetooth.BluetoothHeadsetClient;
     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.List;
     33 
     34 /**
     35  * Handles the Handsfree HF role.
     36  */
     37 final class HfpClientProfile implements LocalBluetoothProfile {
     38     private static final String TAG = "HfpClientProfile";
     39 
     40     private BluetoothHeadsetClient mService;
     41     private boolean mIsProfileReady;
     42 
     43     private final CachedBluetoothDeviceManager mDeviceManager;
     44 
     45     static final ParcelUuid[] SRC_UUIDS = {
     46         BluetoothUuid.HSP_AG,
     47         BluetoothUuid.Handsfree_AG,
     48     };
     49 
     50     static final String NAME = "HEADSET_CLIENT";
     51     private final LocalBluetoothProfileManager mProfileManager;
     52 
     53     // Order of this profile in device profiles list
     54     private static final int ORDINAL = 0;
     55 
     56     // These callbacks run on the main thread.
     57     private final class HfpClientServiceListener
     58             implements BluetoothProfile.ServiceListener {
     59 
     60         @Override
     61         public void onServiceConnected(int profile, BluetoothProfile proxy) {
     62             mService = (BluetoothHeadsetClient) proxy;
     63             // We just bound to the service, so refresh the UI for any connected HFP devices.
     64             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
     65             while (!deviceList.isEmpty()) {
     66                 BluetoothDevice nextDevice = deviceList.remove(0);
     67                 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
     68                 // we may add a new device here, but generally this should not happen
     69                 if (device == null) {
     70                     Log.w(TAG, "HfpClient profile found new device: " + nextDevice);
     71                     device = mDeviceManager.addDevice(nextDevice);
     72                 }
     73                 device.onProfileStateChanged(
     74                     HfpClientProfile.this, BluetoothProfile.STATE_CONNECTED);
     75                 device.refresh();
     76             }
     77             mIsProfileReady=true;
     78         }
     79 
     80         @Override
     81         public void onServiceDisconnected(int profile) {
     82             mIsProfileReady=false;
     83         }
     84     }
     85 
     86     @Override
     87     public boolean isProfileReady() {
     88         return mIsProfileReady;
     89     }
     90 
     91     @Override
     92     public int getProfileId() {
     93         return BluetoothProfile.HEADSET_CLIENT;
     94     }
     95 
     96     HfpClientProfile(Context context, CachedBluetoothDeviceManager deviceManager,
     97             LocalBluetoothProfileManager profileManager) {
     98         mDeviceManager = deviceManager;
     99         mProfileManager = profileManager;
    100         BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
    101                 new HfpClientServiceListener(), BluetoothProfile.HEADSET_CLIENT);
    102     }
    103 
    104     @Override
    105     public boolean accessProfileEnabled() {
    106         return true;
    107     }
    108 
    109     @Override
    110     public boolean isAutoConnectable() {
    111         return true;
    112     }
    113 
    114     public List<BluetoothDevice> getConnectedDevices() {
    115         if (mService == null) {
    116             return new ArrayList<BluetoothDevice>(0);
    117         }
    118         return mService.getDevicesMatchingConnectionStates(
    119               new int[] {BluetoothProfile.STATE_CONNECTED,
    120                          BluetoothProfile.STATE_CONNECTING,
    121                          BluetoothProfile.STATE_DISCONNECTING});
    122     }
    123 
    124     @Override
    125     public boolean connect(BluetoothDevice device) {
    126         if (mService == null) {
    127             return false;
    128         }
    129         return mService.connect(device);
    130     }
    131 
    132     @Override
    133     public boolean disconnect(BluetoothDevice device) {
    134         if (mService == null) {
    135             return false;
    136         }
    137         // Downgrade priority as user is disconnecting the headset.
    138         if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
    139             mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
    140         }
    141         return mService.disconnect(device);
    142     }
    143 
    144     @Override
    145     public int getConnectionStatus(BluetoothDevice device) {
    146         if (mService == null) {
    147             return BluetoothProfile.STATE_DISCONNECTED;
    148         }
    149         return mService.getConnectionState(device);
    150     }
    151 
    152     @Override
    153     public boolean isPreferred(BluetoothDevice device) {
    154         if (mService == null) {
    155             return false;
    156         }
    157         return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
    158     }
    159 
    160     @Override
    161     public int getPreferred(BluetoothDevice device) {
    162         if (mService == null) {
    163             return BluetoothProfile.PRIORITY_OFF;
    164         }
    165         return mService.getPriority(device);
    166     }
    167 
    168     @Override
    169     public void setPreferred(BluetoothDevice device, boolean preferred) {
    170         if (mService == null) {
    171             return;
    172         }
    173         if (preferred) {
    174             if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
    175                 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
    176             }
    177         } else {
    178             mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
    179         }
    180     }
    181 
    182     @Override
    183     public String toString() {
    184         return NAME;
    185     }
    186 
    187     @Override
    188     public int getOrdinal() {
    189         return ORDINAL;
    190     }
    191 
    192     @Override
    193     public int getNameResource(BluetoothDevice device) {
    194         return R.string.bluetooth_profile_headset;
    195     }
    196 
    197     @Override
    198     public int getSummaryResourceForDevice(BluetoothDevice device) {
    199         int state = getConnectionStatus(device);
    200         switch (state) {
    201             case BluetoothProfile.STATE_DISCONNECTED:
    202                 return R.string.bluetooth_headset_profile_summary_use_for;
    203 
    204             case BluetoothProfile.STATE_CONNECTED:
    205                 return R.string.bluetooth_headset_profile_summary_connected;
    206 
    207             default:
    208                 return BluetoothUtils.getConnectionStateSummary(state);
    209         }
    210     }
    211 
    212     @Override
    213     public int getDrawableResource(BluetoothClass btClass) {
    214         return com.android.internal.R.drawable.ic_bt_headset_hfp;
    215     }
    216 
    217     protected void finalize() {
    218         Log.d(TAG, "finalize()");
    219         if (mService != null) {
    220             try {
    221                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
    222                     BluetoothProfile.HEADSET_CLIENT, mService);
    223                 mService = null;
    224             } catch (Throwable t) {
    225                 Log.w(TAG, "Error cleaning up HfpClient proxy", t);
    226             }
    227         }
    228     }
    229 }
    230