Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2008 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.annotation.UnsupportedAppUsage;
     20 import android.content.Context;
     21 import android.os.Binder;
     22 import android.os.IBinder;
     23 import android.os.RemoteException;
     24 import android.util.Log;
     25 
     26 import java.util.ArrayList;
     27 import java.util.List;
     28 
     29 /**
     30  * This class provides the APIs to control the Bluetooth SIM
     31  * Access Profile (SAP).
     32  *
     33  * <p>BluetoothSap is a proxy object for controlling the Bluetooth
     34  * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
     35  * the BluetoothSap proxy object.
     36  *
     37  * <p>Each method is protected with its appropriate permission.
     38  *
     39  * @hide
     40  */
     41 public final class BluetoothSap implements BluetoothProfile {
     42 
     43     private static final String TAG = "BluetoothSap";
     44     private static final boolean DBG = true;
     45     private static final boolean VDBG = false;
     46 
     47     /**
     48      * Intent used to broadcast the change in connection state of the profile.
     49      *
     50      * <p>This intent will have 4 extras:
     51      * <ul>
     52      * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
     53      * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
     54      * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
     55      * </ul>
     56      *
     57      * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
     58      * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
     59      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
     60      *
     61      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
     62      * receive.
     63      *
     64      * @hide
     65      */
     66     public static final String ACTION_CONNECTION_STATE_CHANGED =
     67             "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
     68 
     69     /**
     70      * There was an error trying to obtain the state.
     71      *
     72      * @hide
     73      */
     74     public static final int STATE_ERROR = -1;
     75 
     76     /**
     77      * Connection state change succceeded.
     78      *
     79      * @hide
     80      */
     81     public static final int RESULT_SUCCESS = 1;
     82 
     83     /**
     84      * Connection canceled before completion.
     85      *
     86      * @hide
     87      */
     88     public static final int RESULT_CANCELED = 2;
     89 
     90     private BluetoothAdapter mAdapter;
     91     private final BluetoothProfileConnector<IBluetoothSap> mProfileConnector =
     92             new BluetoothProfileConnector(this, BluetoothProfile.SAP,
     93                     "BluetoothSap", IBluetoothSap.class.getName()) {
     94                 @Override
     95                 public IBluetoothSap getServiceInterface(IBinder service) {
     96                     return IBluetoothSap.Stub.asInterface(Binder.allowBlocking(service));
     97                 }
     98     };
     99 
    100     /**
    101      * Create a BluetoothSap proxy object.
    102      */
    103     /*package*/ BluetoothSap(Context context, ServiceListener listener) {
    104         if (DBG) Log.d(TAG, "Create BluetoothSap proxy object");
    105         mAdapter = BluetoothAdapter.getDefaultAdapter();
    106         mProfileConnector.connect(context, listener);
    107     }
    108 
    109     protected void finalize() throws Throwable {
    110         try {
    111             close();
    112         } finally {
    113             super.finalize();
    114         }
    115     }
    116 
    117     /**
    118      * Close the connection to the backing service.
    119      * Other public functions of BluetoothSap will return default error
    120      * results once close() has been called. Multiple invocations of close()
    121      * are ok.
    122      *
    123      * @hide
    124      */
    125     public synchronized void close() {
    126         mProfileConnector.disconnect();
    127     }
    128 
    129     private IBluetoothSap getService() {
    130         return mProfileConnector.getService();
    131     }
    132 
    133     /**
    134      * Get the current state of the BluetoothSap service.
    135      *
    136      * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not
    137      * connected to the Sap service.
    138      * @hide
    139      */
    140     public int getState() {
    141         if (VDBG) log("getState()");
    142         final IBluetoothSap service = getService();
    143         if (service != null) {
    144             try {
    145                 return service.getState();
    146             } catch (RemoteException e) {
    147                 Log.e(TAG, e.toString());
    148             }
    149         } else {
    150             Log.w(TAG, "Proxy not attached to service");
    151             if (DBG) log(Log.getStackTraceString(new Throwable()));
    152         }
    153         return BluetoothSap.STATE_ERROR;
    154     }
    155 
    156     /**
    157      * Get the currently connected remote Bluetooth device (PCE).
    158      *
    159      * @return The remote Bluetooth device, or null if not in connected or connecting state, or if
    160      * this proxy object is not connected to the Sap service.
    161      * @hide
    162      */
    163     public BluetoothDevice getClient() {
    164         if (VDBG) log("getClient()");
    165         final IBluetoothSap service = getService();
    166         if (service != null) {
    167             try {
    168                 return service.getClient();
    169             } catch (RemoteException e) {
    170                 Log.e(TAG, e.toString());
    171             }
    172         } else {
    173             Log.w(TAG, "Proxy not attached to service");
    174             if (DBG) log(Log.getStackTraceString(new Throwable()));
    175         }
    176         return null;
    177     }
    178 
    179     /**
    180      * Returns true if the specified Bluetooth device is connected.
    181      * Returns false if not connected, or if this proxy object is not
    182      * currently connected to the Sap service.
    183      *
    184      * @hide
    185      */
    186     public boolean isConnected(BluetoothDevice device) {
    187         if (VDBG) log("isConnected(" + device + ")");
    188         final IBluetoothSap service = getService();
    189         if (service != null) {
    190             try {
    191                 return service.isConnected(device);
    192             } catch (RemoteException e) {
    193                 Log.e(TAG, e.toString());
    194             }
    195         } else {
    196             Log.w(TAG, "Proxy not attached to service");
    197             if (DBG) log(Log.getStackTraceString(new Throwable()));
    198         }
    199         return false;
    200     }
    201 
    202     /**
    203      * Initiate connection. Initiation of outgoing connections is not
    204      * supported for SAP server.
    205      *
    206      * @hide
    207      */
    208     public boolean connect(BluetoothDevice device) {
    209         if (DBG) log("connect(" + device + ")" + "not supported for SAPS");
    210         return false;
    211     }
    212 
    213     /**
    214      * Initiate disconnect.
    215      *
    216      * @param device Remote Bluetooth Device
    217      * @return false on error, true otherwise
    218      * @hide
    219      */
    220     @UnsupportedAppUsage
    221     public boolean disconnect(BluetoothDevice device) {
    222         if (DBG) log("disconnect(" + device + ")");
    223         final IBluetoothSap service = getService();
    224         if (service != null && isEnabled() && isValidDevice(device)) {
    225             try {
    226                 return service.disconnect(device);
    227             } catch (RemoteException e) {
    228                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    229                 return false;
    230             }
    231         }
    232         if (service == null) Log.w(TAG, "Proxy not attached to service");
    233         return false;
    234     }
    235 
    236     /**
    237      * Get the list of connected devices. Currently at most one.
    238      *
    239      * @return list of connected devices
    240      * @hide
    241      */
    242     public List<BluetoothDevice> getConnectedDevices() {
    243         if (DBG) log("getConnectedDevices()");
    244         final IBluetoothSap service = getService();
    245         if (service != null && isEnabled()) {
    246             try {
    247                 return service.getConnectedDevices();
    248             } catch (RemoteException e) {
    249                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    250                 return new ArrayList<BluetoothDevice>();
    251             }
    252         }
    253         if (service == null) Log.w(TAG, "Proxy not attached to service");
    254         return new ArrayList<BluetoothDevice>();
    255     }
    256 
    257     /**
    258      * Get the list of devices matching specified states. Currently at most one.
    259      *
    260      * @return list of matching devices
    261      * @hide
    262      */
    263     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    264         if (DBG) log("getDevicesMatchingStates()");
    265         final IBluetoothSap service = getService();
    266         if (service != null && isEnabled()) {
    267             try {
    268                 return service.getDevicesMatchingConnectionStates(states);
    269             } catch (RemoteException e) {
    270                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    271                 return new ArrayList<BluetoothDevice>();
    272             }
    273         }
    274         if (service == null) Log.w(TAG, "Proxy not attached to service");
    275         return new ArrayList<BluetoothDevice>();
    276     }
    277 
    278     /**
    279      * Get connection state of device
    280      *
    281      * @return device connection state
    282      * @hide
    283      */
    284     public int getConnectionState(BluetoothDevice device) {
    285         if (DBG) log("getConnectionState(" + device + ")");
    286         final IBluetoothSap service = getService();
    287         if (service != null && isEnabled() && isValidDevice(device)) {
    288             try {
    289                 return service.getConnectionState(device);
    290             } catch (RemoteException e) {
    291                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    292                 return BluetoothProfile.STATE_DISCONNECTED;
    293             }
    294         }
    295         if (service == null) Log.w(TAG, "Proxy not attached to service");
    296         return BluetoothProfile.STATE_DISCONNECTED;
    297     }
    298 
    299     /**
    300      * Set priority of the profile
    301      *
    302      * <p> The device should already be paired.
    303      *
    304      * @param device Paired bluetooth device
    305      * @param priority
    306      * @return true if priority is set, false on error
    307      * @hide
    308      */
    309     public boolean setPriority(BluetoothDevice device, int priority) {
    310         if (DBG) log("setPriority(" + device + ", " + priority + ")");
    311         final IBluetoothSap service = getService();
    312         if (service != null && isEnabled() && isValidDevice(device)) {
    313             if (priority != BluetoothProfile.PRIORITY_OFF
    314                     && priority != BluetoothProfile.PRIORITY_ON) {
    315                 return false;
    316             }
    317             try {
    318                 return service.setPriority(device, priority);
    319             } catch (RemoteException e) {
    320                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    321                 return false;
    322             }
    323         }
    324         if (service == null) Log.w(TAG, "Proxy not attached to service");
    325         return false;
    326     }
    327 
    328     /**
    329      * Get the priority of the profile.
    330      *
    331      * @param device Bluetooth device
    332      * @return priority of the device
    333      * @hide
    334      */
    335     public int getPriority(BluetoothDevice device) {
    336         if (VDBG) log("getPriority(" + device + ")");
    337         final IBluetoothSap service = getService();
    338         if (service != null && isEnabled() && isValidDevice(device)) {
    339             try {
    340                 return service.getPriority(device);
    341             } catch (RemoteException e) {
    342                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
    343                 return PRIORITY_OFF;
    344             }
    345         }
    346         if (service == null) Log.w(TAG, "Proxy not attached to service");
    347         return PRIORITY_OFF;
    348     }
    349 
    350     private static void log(String msg) {
    351         Log.d(TAG, msg);
    352     }
    353 
    354     private boolean isEnabled() {
    355         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    356 
    357         if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) {
    358             return true;
    359         }
    360         log("Bluetooth is Not enabled");
    361         return false;
    362     }
    363 
    364     private static boolean isValidDevice(BluetoothDevice device) {
    365         return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
    366     }
    367 
    368 }
    369