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.SdkConstant;
     20 import android.annotation.SdkConstant.SdkConstantType;
     21 import android.content.Context;
     22 import android.os.IBinder;
     23 import android.os.RemoteException;
     24 import android.os.ServiceManager;
     25 import android.util.Log;
     26 
     27 import java.util.ArrayList;
     28 import java.util.List;
     29 
     30 
     31 /**
     32  * This class provides the APIs to control the Bluetooth Pan
     33  * Profile.
     34  *
     35  *<p>BluetoothPan is a proxy object for controlling the Bluetooth
     36  * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
     37  * the BluetoothPan proxy object.
     38  *
     39  *<p>Each method is protected with its appropriate permission.
     40  *@hide
     41  */
     42 public final class BluetoothPan implements BluetoothProfile {
     43     private static final String TAG = "BluetoothPan";
     44     private static final boolean DBG = false;
     45 
     46     /**
     47      * Intent used to broadcast the change in connection state of the Pan
     48      * 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      *   <li> {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is
     56      *   bound to. </li>
     57      * </ul>
     58      *
     59      * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
     60      * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
     61      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
     62      *
     63      * <p> {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or
     64      * {@link #LOCAL_PANU_ROLE}
     65      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
     66      * receive.
     67      */
     68     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     69     public static final String ACTION_CONNECTION_STATE_CHANGED =
     70         "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
     71 
     72     /**
     73      * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent
     74      * The local role of the PAN profile that the remote device is bound to.
     75      * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}.
     76      */
     77     public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
     78 
     79     /**
     80      * The local device is acting as a Network Access Point.
     81      */
     82     public static final int LOCAL_NAP_ROLE = 1;
     83 
     84     /**
     85      * The local device is acting as a PAN User.
     86      */
     87     public static final int LOCAL_PANU_ROLE = 2;
     88 
     89     /**
     90      * Return codes for the connect and disconnect Bluez / Dbus calls.
     91      * @hide
     92      */
     93     public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000;
     94 
     95     /**
     96      * @hide
     97      */
     98     public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001;
     99 
    100     /**
    101      * @hide
    102      */
    103     public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002;
    104 
    105     /**
    106      * @hide
    107      */
    108     public static final int PAN_OPERATION_GENERIC_FAILURE = 1003;
    109 
    110     /**
    111      * @hide
    112      */
    113     public static final int PAN_OPERATION_SUCCESS = 1004;
    114 
    115     private ServiceListener mServiceListener;
    116     private BluetoothAdapter mAdapter;
    117     private IBluetooth mService;
    118 
    119     /**
    120      * Create a BluetoothPan proxy object for interacting with the local
    121      * Bluetooth Service which handles the Pan profile
    122      *
    123      */
    124     /*package*/ BluetoothPan(Context mContext, ServiceListener l) {
    125         IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
    126         mServiceListener = l;
    127         mAdapter = BluetoothAdapter.getDefaultAdapter();
    128         if (b != null) {
    129             mService = IBluetooth.Stub.asInterface(b);
    130             if (mServiceListener != null) {
    131                 mServiceListener.onServiceConnected(BluetoothProfile.PAN, this);
    132             }
    133         } else {
    134             Log.w(TAG, "Bluetooth Service not available!");
    135 
    136             // Instead of throwing an exception which prevents people from going
    137             // into Wireless settings in the emulator. Let it crash later when it is actually used.
    138             mService = null;
    139         }
    140     }
    141 
    142     /*package*/ void close() {
    143         mServiceListener = null;
    144     }
    145 
    146     /**
    147      * Initiate connection to a profile of the remote bluetooth device.
    148      *
    149      * <p> This API returns false in scenarios like the profile on the
    150      * device is already connected or Bluetooth is not turned on.
    151      * When this API returns true, it is guaranteed that
    152      * connection state intent for the profile will be broadcasted with
    153      * the state. Users can get the connection state of the profile
    154      * from this intent.
    155      *
    156      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    157      * permission.
    158      *
    159      * @param device Remote Bluetooth Device
    160      * @return false on immediate error,
    161      *               true otherwise
    162      * @hide
    163      */
    164     public boolean connect(BluetoothDevice device) {
    165         if (DBG) log("connect(" + device + ")");
    166         if (mService != null && isEnabled() &&
    167             isValidDevice(device)) {
    168             try {
    169                 return mService.connectPanDevice(device);
    170             } catch (RemoteException e) {
    171                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    172                 return false;
    173             }
    174         }
    175         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    176         return false;
    177     }
    178 
    179     /**
    180      * Initiate disconnection from a profile
    181      *
    182      * <p> This API will return false in scenarios like the profile on the
    183      * Bluetooth device is not in connected state etc. When this API returns,
    184      * true, it is guaranteed that the connection state change
    185      * intent will be broadcasted with the state. Users can get the
    186      * disconnection state of the profile from this intent.
    187      *
    188      * <p> If the disconnection is initiated by a remote device, the state
    189      * will transition from {@link #STATE_CONNECTED} to
    190      * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
    191      * host (local) device the state will transition from
    192      * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
    193      * state {@link #STATE_DISCONNECTED}. The transition to
    194      * {@link #STATE_DISCONNECTING} can be used to distinguish between the
    195      * two scenarios.
    196      *
    197      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    198      * permission.
    199      *
    200      * @param device Remote Bluetooth Device
    201      * @return false on immediate error,
    202      *               true otherwise
    203      * @hide
    204      */
    205     public boolean disconnect(BluetoothDevice device) {
    206         if (DBG) log("disconnect(" + device + ")");
    207         if (mService != null && isEnabled() &&
    208             isValidDevice(device)) {
    209             try {
    210                 return mService.disconnectPanDevice(device);
    211             } catch (RemoteException e) {
    212                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    213                 return false;
    214             }
    215         }
    216         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    217         return false;
    218     }
    219 
    220     /**
    221      * {@inheritDoc}
    222      */
    223     public List<BluetoothDevice> getConnectedDevices() {
    224         if (DBG) log("getConnectedDevices()");
    225         if (mService != null && isEnabled()) {
    226             try {
    227                 return mService.getConnectedPanDevices();
    228             } catch (RemoteException e) {
    229                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    230                 return new ArrayList<BluetoothDevice>();
    231             }
    232         }
    233         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    234         return new ArrayList<BluetoothDevice>();
    235     }
    236 
    237     /**
    238      * {@inheritDoc}
    239      */
    240     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    241         if (DBG) log("getDevicesMatchingStates()");
    242         if (mService != null && isEnabled()) {
    243             try {
    244                 return mService.getPanDevicesMatchingConnectionStates(states);
    245             } catch (RemoteException e) {
    246                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    247                 return new ArrayList<BluetoothDevice>();
    248             }
    249         }
    250         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    251         return new ArrayList<BluetoothDevice>();
    252     }
    253 
    254     /**
    255      * {@inheritDoc}
    256      */
    257     public int getConnectionState(BluetoothDevice device) {
    258         if (DBG) log("getState(" + device + ")");
    259         if (mService != null && isEnabled()
    260             && isValidDevice(device)) {
    261             try {
    262                 return mService.getPanDeviceConnectionState(device);
    263             } catch (RemoteException e) {
    264                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    265                 return BluetoothProfile.STATE_DISCONNECTED;
    266             }
    267         }
    268         if (mService == null) Log.w(TAG, "Proxy not attached to service");
    269         return BluetoothProfile.STATE_DISCONNECTED;
    270     }
    271 
    272     public void setBluetoothTethering(boolean value) {
    273         if (DBG) log("setBluetoothTethering(" + value + ")");
    274         try {
    275             mService.setBluetoothTethering(value);
    276         } catch (RemoteException e) {
    277             Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    278         }
    279     }
    280 
    281     public boolean isTetheringOn() {
    282         if (DBG) log("isTetheringOn()");
    283         try {
    284             return mService.isTetheringOn();
    285         } catch (RemoteException e) {
    286             Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
    287             return false;
    288         }
    289     }
    290 
    291     private boolean isEnabled() {
    292        if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
    293        return false;
    294     }
    295 
    296     private boolean isValidDevice(BluetoothDevice device) {
    297        if (device == null) return false;
    298 
    299        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
    300        return false;
    301     }
    302 
    303     private static void log(String msg) {
    304       Log.d(TAG, msg);
    305     }
    306 }
    307