• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
BluetoothPan(Context mContext, ServiceListener l)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 
close()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      */
connect(BluetoothDevice device)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      */
disconnect(BluetoothDevice device)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      */
getConnectedDevices()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      */
getDevicesMatchingConnectionStates(int[] states)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      */
getConnectionState(BluetoothDevice device)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 
setBluetoothTethering(boolean value)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 
isTetheringOn()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 
isEnabled()291     private boolean isEnabled() {
292        if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
293        return false;
294     }
295 
isValidDevice(BluetoothDevice device)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 
log(String msg)303     private static void log(String msg) {
304       Log.d(TAG, msg);
305     }
306 }
307