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 android.bluetooth;
     18 
     19 import android.content.Context;
     20 import android.os.Binder;
     21 import android.os.IBinder;
     22 import android.os.RemoteException;
     23 import android.util.Log;
     24 
     25 import java.util.ArrayList;
     26 import java.util.List;
     27 
     28 /**
     29  * This class provides the APIs to control the Bluetooth PBAP Client Profile.
     30  *
     31  * @hide
     32  */
     33 public final class BluetoothPbapClient implements BluetoothProfile {
     34 
     35     private static final String TAG = "BluetoothPbapClient";
     36     private static final boolean DBG = false;
     37     private static final boolean VDBG = false;
     38 
     39     public static final String ACTION_CONNECTION_STATE_CHANGED =
     40             "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED";
     41 
     42     /** There was an error trying to obtain the state */
     43     public static final int STATE_ERROR = -1;
     44 
     45     public static final int RESULT_FAILURE = 0;
     46     public static final int RESULT_SUCCESS = 1;
     47     /** Connection canceled before completion. */
     48     public static final int RESULT_CANCELED = 2;
     49 
     50     private BluetoothAdapter mAdapter;
     51     private final BluetoothProfileConnector<IBluetoothPbapClient> mProfileConnector =
     52             new BluetoothProfileConnector(this, BluetoothProfile.PBAP_CLIENT,
     53                     "BluetoothPbapClient", IBluetoothPbapClient.class.getName()) {
     54                 @Override
     55                 public IBluetoothPbapClient getServiceInterface(IBinder service) {
     56                     return IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service));
     57                 }
     58     };
     59 
     60     /**
     61      * Create a BluetoothPbapClient proxy object.
     62      */
     63     BluetoothPbapClient(Context context, ServiceListener listener) {
     64         if (DBG) {
     65             Log.d(TAG, "Create BluetoothPbapClient proxy object");
     66         }
     67         mAdapter = BluetoothAdapter.getDefaultAdapter();
     68         mProfileConnector.connect(context, listener);
     69     }
     70 
     71     protected void finalize() throws Throwable {
     72         try {
     73             close();
     74         } finally {
     75             super.finalize();
     76         }
     77     }
     78 
     79     /**
     80      * Close the connection to the backing service.
     81      * Other public functions of BluetoothPbapClient will return default error
     82      * results once close() has been called. Multiple invocations of close()
     83      * are ok.
     84      */
     85     public synchronized void close() {
     86         mProfileConnector.disconnect();
     87     }
     88 
     89     private IBluetoothPbapClient getService() {
     90         return mProfileConnector.getService();
     91     }
     92 
     93     /**
     94      * Initiate connection.
     95      * Upon successful connection to remote PBAP server the Client will
     96      * attempt to automatically download the users phonebook and call log.
     97      *
     98      * @param device a remote device we want connect to
     99      * @return <code>true</code> if command has been issued successfully; <code>false</code>
    100      * otherwise;
    101      */
    102     public boolean connect(BluetoothDevice device) {
    103         if (DBG) {
    104             log("connect(" + device + ") for PBAP Client.");
    105         }
    106         final IBluetoothPbapClient service = getService();
    107         if (service != null && isEnabled() && isValidDevice(device)) {
    108             try {
    109                 return service.connect(device);
    110             } catch (RemoteException e) {
    111                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    112                 return false;
    113             }
    114         }
    115         if (service == null) {
    116             Log.w(TAG, "Proxy not attached to service");
    117         }
    118         return false;
    119     }
    120 
    121     /**
    122      * Initiate disconnect.
    123      *
    124      * @param device Remote Bluetooth Device
    125      * @return false on error, true otherwise
    126      */
    127     public boolean disconnect(BluetoothDevice device) {
    128         if (DBG) {
    129             log("disconnect(" + device + ")" + new Exception());
    130         }
    131         final IBluetoothPbapClient service = getService();
    132         if (service != null && isEnabled() && isValidDevice(device)) {
    133             try {
    134                 service.disconnect(device);
    135                 return true;
    136             } catch (RemoteException e) {
    137                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    138                 return false;
    139             }
    140         }
    141         if (service == null) {
    142             Log.w(TAG, "Proxy not attached to service");
    143         }
    144         return false;
    145     }
    146 
    147     /**
    148      * Get the list of connected devices.
    149      * Currently at most one.
    150      *
    151      * @return list of connected devices
    152      */
    153     @Override
    154     public List<BluetoothDevice> getConnectedDevices() {
    155         if (DBG) {
    156             log("getConnectedDevices()");
    157         }
    158         final IBluetoothPbapClient service = getService();
    159         if (service != null && isEnabled()) {
    160             try {
    161                 return service.getConnectedDevices();
    162             } catch (RemoteException e) {
    163                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    164                 return new ArrayList<BluetoothDevice>();
    165             }
    166         }
    167         if (service == null) {
    168             Log.w(TAG, "Proxy not attached to service");
    169         }
    170         return new ArrayList<BluetoothDevice>();
    171     }
    172 
    173     /**
    174      * Get the list of devices matching specified states. Currently at most one.
    175      *
    176      * @return list of matching devices
    177      */
    178     @Override
    179     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    180         if (DBG) {
    181             log("getDevicesMatchingStates()");
    182         }
    183         final IBluetoothPbapClient service = getService();
    184         if (service != null && isEnabled()) {
    185             try {
    186                 return service.getDevicesMatchingConnectionStates(states);
    187             } catch (RemoteException e) {
    188                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    189                 return new ArrayList<BluetoothDevice>();
    190             }
    191         }
    192         if (service == null) {
    193             Log.w(TAG, "Proxy not attached to service");
    194         }
    195         return new ArrayList<BluetoothDevice>();
    196     }
    197 
    198     /**
    199      * Get connection state of device
    200      *
    201      * @return device connection state
    202      */
    203     @Override
    204     public int getConnectionState(BluetoothDevice device) {
    205         if (DBG) {
    206             log("getConnectionState(" + device + ")");
    207         }
    208         final IBluetoothPbapClient service = getService();
    209         if (service != null && isEnabled() && isValidDevice(device)) {
    210             try {
    211                 return service.getConnectionState(device);
    212             } catch (RemoteException e) {
    213                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    214                 return BluetoothProfile.STATE_DISCONNECTED;
    215             }
    216         }
    217         if (service == null) {
    218             Log.w(TAG, "Proxy not attached to service");
    219         }
    220         return BluetoothProfile.STATE_DISCONNECTED;
    221     }
    222 
    223     private static void log(String msg) {
    224         Log.d(TAG, msg);
    225     }
    226 
    227     private boolean isEnabled() {
    228         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    229         if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) {
    230             return true;
    231         }
    232         log("Bluetooth is Not enabled");
    233         return false;
    234     }
    235 
    236     private static boolean isValidDevice(BluetoothDevice device) {
    237         return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
    238     }
    239 
    240     /**
    241      * Set priority of the profile
    242      *
    243      * <p> The device should already be paired.
    244      * Priority can be one of {@link #PRIORITY_ON} or
    245      * {@link #PRIORITY_OFF},
    246      *
    247      * @param device Paired bluetooth device
    248      * @param priority Priority of this profile
    249      * @return true if priority is set, false on error
    250      */
    251     public boolean setPriority(BluetoothDevice device, int priority) {
    252         if (DBG) {
    253             log("setPriority(" + device + ", " + priority + ")");
    254         }
    255         final IBluetoothPbapClient service = getService();
    256         if (service != null && isEnabled() && isValidDevice(device)) {
    257             if (priority != BluetoothProfile.PRIORITY_OFF
    258                     && priority != BluetoothProfile.PRIORITY_ON) {
    259                 return false;
    260             }
    261             try {
    262                 return service.setPriority(device, priority);
    263             } catch (RemoteException e) {
    264                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    265                 return false;
    266             }
    267         }
    268         if (service == null) {
    269             Log.w(TAG, "Proxy not attached to service");
    270         }
    271         return false;
    272     }
    273 
    274     /**
    275      * Get the priority of the profile.
    276      *
    277      * <p> The priority can be any of:
    278      * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
    279      * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
    280      *
    281      * @param device Bluetooth device
    282      * @return priority of the device
    283      */
    284     public int getPriority(BluetoothDevice device) {
    285         if (VDBG) {
    286             log("getPriority(" + device + ")");
    287         }
    288         final IBluetoothPbapClient service = getService();
    289         if (service != null && isEnabled() && isValidDevice(device)) {
    290             try {
    291                 return service.getPriority(device);
    292             } catch (RemoteException e) {
    293                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    294                 return PRIORITY_OFF;
    295             }
    296         }
    297         if (service == null) {
    298             Log.w(TAG, "Proxy not attached to service");
    299         }
    300         return PRIORITY_OFF;
    301     }
    302 }
    303