• 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 
142     /**
143      * Initiate connection to a profile of the remote bluetooth device.
144      *
145      * <p> This API returns false in scenarios like the profile on the
146      * device is already connected or Bluetooth is not turned on.
147      * When this API returns true, it is guaranteed that
148      * connection state intent for the profile will be broadcasted with
149      * the state. Users can get the connection state of the profile
150      * from this intent.
151      *
152      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
153      * permission.
154      *
155      * @param device Remote Bluetooth Device
156      * @return false on immediate error,
157      *               true otherwise
158      * @hide
159      */
connect(BluetoothDevice device)160     public boolean connect(BluetoothDevice device) {
161         if (DBG) log("connect(" + device + ")");
162         if (mService != null && isEnabled() &&
163             isValidDevice(device)) {
164             try {
165                 return mService.connectPanDevice(device);
166             } catch (RemoteException e) {
167                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
168                 return false;
169             }
170         }
171         if (mService == null) Log.w(TAG, "Proxy not attached to service");
172         return false;
173     }
174 
175     /**
176      * Initiate disconnection from a profile
177      *
178      * <p> This API will return false in scenarios like the profile on the
179      * Bluetooth device is not in connected state etc. When this API returns,
180      * true, it is guaranteed that the connection state change
181      * intent will be broadcasted with the state. Users can get the
182      * disconnection state of the profile from this intent.
183      *
184      * <p> If the disconnection is initiated by a remote device, the state
185      * will transition from {@link #STATE_CONNECTED} to
186      * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
187      * host (local) device the state will transition from
188      * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
189      * state {@link #STATE_DISCONNECTED}. The transition to
190      * {@link #STATE_DISCONNECTING} can be used to distinguish between the
191      * two scenarios.
192      *
193      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
194      * permission.
195      *
196      * @param device Remote Bluetooth Device
197      * @return false on immediate error,
198      *               true otherwise
199      * @hide
200      */
disconnect(BluetoothDevice device)201     public boolean disconnect(BluetoothDevice device) {
202         if (DBG) log("disconnect(" + device + ")");
203         if (mService != null && isEnabled() &&
204             isValidDevice(device)) {
205             try {
206                 return mService.disconnectPanDevice(device);
207             } catch (RemoteException e) {
208                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
209                 return false;
210             }
211         }
212         if (mService == null) Log.w(TAG, "Proxy not attached to service");
213         return false;
214     }
215 
216     /**
217      * {@inheritDoc}
218      */
getConnectedDevices()219     public List<BluetoothDevice> getConnectedDevices() {
220         if (DBG) log("getConnectedDevices()");
221         if (mService != null && isEnabled()) {
222             try {
223                 return mService.getConnectedPanDevices();
224             } catch (RemoteException e) {
225                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
226                 return new ArrayList<BluetoothDevice>();
227             }
228         }
229         if (mService == null) Log.w(TAG, "Proxy not attached to service");
230         return new ArrayList<BluetoothDevice>();
231     }
232 
233     /**
234      * {@inheritDoc}
235      */
getDevicesMatchingConnectionStates(int[] states)236     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
237         if (DBG) log("getDevicesMatchingStates()");
238         if (mService != null && isEnabled()) {
239             try {
240                 return mService.getPanDevicesMatchingConnectionStates(states);
241             } catch (RemoteException e) {
242                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
243                 return new ArrayList<BluetoothDevice>();
244             }
245         }
246         if (mService == null) Log.w(TAG, "Proxy not attached to service");
247         return new ArrayList<BluetoothDevice>();
248     }
249 
250     /**
251      * {@inheritDoc}
252      */
getConnectionState(BluetoothDevice device)253     public int getConnectionState(BluetoothDevice device) {
254         if (DBG) log("getState(" + device + ")");
255         if (mService != null && isEnabled()
256             && isValidDevice(device)) {
257             try {
258                 return mService.getPanDeviceConnectionState(device);
259             } catch (RemoteException e) {
260                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
261                 return BluetoothProfile.STATE_DISCONNECTED;
262             }
263         }
264         if (mService == null) Log.w(TAG, "Proxy not attached to service");
265         return BluetoothProfile.STATE_DISCONNECTED;
266     }
267 
setBluetoothTethering(boolean value)268     public void setBluetoothTethering(boolean value) {
269         if (DBG) log("setBluetoothTethering(" + value + ")");
270         try {
271             mService.setBluetoothTethering(value);
272         } catch (RemoteException e) {
273             Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
274         }
275     }
276 
isTetheringOn()277     public boolean isTetheringOn() {
278         if (DBG) log("isTetheringOn()");
279         try {
280             return mService.isTetheringOn();
281         } catch (RemoteException e) {
282             Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
283             return false;
284         }
285     }
286 
isEnabled()287     private boolean isEnabled() {
288        if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
289        return false;
290     }
291 
isValidDevice(BluetoothDevice device)292     private boolean isValidDevice(BluetoothDevice device) {
293        if (device == null) return false;
294 
295        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
296        return false;
297     }
298 
log(String msg)299     private static void log(String msg) {
300       Log.d(TAG, msg);
301     }
302 }