blob: 282b70a42c8145a485b09a512e04e23d397e0261 [file] [log] [blame]
Jaikumar Ganesh545e6702010-06-04 10:23:03 -07001/*
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -08002 * Copyright (C) 2011 The Android Open Source Project
Jaikumar Ganesh545e6702010-06-04 10:23:03 -07003 *
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
17package android.bluetooth;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.content.Context;
22import android.os.IBinder;
23import android.os.RemoteException;
24import android.os.ServiceManager;
25import android.util.Log;
26
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070027import java.util.ArrayList;
28import java.util.List;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070029
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080030
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070031/**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080032 * This class provides the public APIs to control the Bluetooth Input
33 * Device Profile.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070034 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080035 *<p>BluetoothInputDevice is a proxy object for controlling the Bluetooth
36 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
37 * the BluetoothInputDevice proxy object.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070038 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080039 *<p>Each method is protected with its appropriate permission.
40 *@hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070041 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080042public final class BluetoothInputDevice implements BluetoothProfile {
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070043 private static final String TAG = "BluetoothInputDevice";
44 private static final boolean DBG = false;
45
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080046 /**
47 * Intent used to broadcast the change in connection state of the Input
48 * Device profile.
49 *
50 * <p>This intent will have 3 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.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070063 */
64 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080065 public static final String ACTION_CONNECTION_STATE_CHANGED =
66 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070067
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080068 /**
69 * Return codes for the connect and disconnect Bluez / Dbus calls.
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080070 * @hide
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080071 */
72 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
73
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080074 /**
75 * @hide
76 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080077 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
78
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080079 /**
80 * @hide
81 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080082 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
83
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080084 /**
85 * @hide
86 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080087 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
88
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080089 /**
90 * @hide
91 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080092 public static final int INPUT_OPERATION_SUCCESS = 5004;
93
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080094 private ServiceListener mServiceListener;
95 private BluetoothAdapter mAdapter;
96 private IBluetooth mService;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070097
98 /**
99 * Create a BluetoothInputDevice proxy object for interacting with the local
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800100 * Bluetooth Service which handles the InputDevice profile
101 *
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700102 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800103 /*package*/ BluetoothInputDevice(Context mContext, ServiceListener l) {
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700104 IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800105 mServiceListener = l;
106 mAdapter = BluetoothAdapter.getDefaultAdapter();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700107 if (b != null) {
108 mService = IBluetooth.Stub.asInterface(b);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800109 if (mServiceListener != null) {
110 mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, this);
111 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700112 } else {
113 Log.w(TAG, "Bluetooth Service not available!");
114
115 // Instead of throwing an exception which prevents people from going
116 // into Wireless settings in the emulator. Let it crash later when it is actually used.
117 mService = null;
118 }
119 }
120
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800121 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700122 * Initiate connection to a profile of the remote bluetooth device.
123 *
124 * <p> The system supports connection to multiple input devices.
125 *
126 * <p> This API returns false in scenarios like the profile on the
127 * device is already connected or Bluetooth is not turned on.
128 * When this API returns true, it is guaranteed that
129 * connection state intent for the profile will be broadcasted with
130 * the state. Users can get the connection state of the profile
131 * from this intent.
132 *
133 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
134 * permission.
135 *
136 * @param device Remote Bluetooth Device
137 * @return false on immediate error,
138 * true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800139 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700140 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800141 public boolean connect(BluetoothDevice device) {
142 if (DBG) log("connect(" + device + ")");
143 if (mService != null && isEnabled() &&
144 isValidDevice(device)) {
145 try {
146 return mService.connectInputDevice(device);
147 } catch (RemoteException e) {
148 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
149 return false;
150 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700151 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800152 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700153 return false;
154 }
155
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800156 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700157 * Initiate disconnection from a profile
158 *
159 * <p> This API will return false in scenarios like the profile on the
160 * Bluetooth device is not in connected state etc. When this API returns,
161 * true, it is guaranteed that the connection state change
162 * intent will be broadcasted with the state. Users can get the
163 * disconnection state of the profile from this intent.
164 *
165 * <p> If the disconnection is initiated by a remote device, the state
166 * will transition from {@link #STATE_CONNECTED} to
167 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
168 * host (local) device the state will transition from
169 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
170 * state {@link #STATE_DISCONNECTED}. The transition to
171 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
172 * two scenarios.
173 *
174 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
175 * permission.
176 *
177 * @param device Remote Bluetooth Device
178 * @return false on immediate error,
179 * true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700180 * @hide
181 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800182 public boolean disconnect(BluetoothDevice device) {
183 if (DBG) log("disconnect(" + device + ")");
184 if (mService != null && isEnabled() &&
185 isValidDevice(device)) {
186 try {
187 return mService.disconnectInputDevice(device);
188 } catch (RemoteException e) {
189 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
190 return false;
191 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700192 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800193 if (mService == null) Log.w(TAG, "Proxy not attached to service");
194 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700195 }
196
197 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800198 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700199 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800200 public List<BluetoothDevice> getConnectedDevices() {
201 if (DBG) log("getConnectedDevices()");
202 if (mService != null && isEnabled()) {
203 try {
204 return mService.getConnectedInputDevices();
205 } catch (RemoteException e) {
206 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
207 return new ArrayList<BluetoothDevice>();
208 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700209 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800210 if (mService == null) Log.w(TAG, "Proxy not attached to service");
211 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700212 }
213
214 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800215 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700216 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800217 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
218 if (DBG) log("getDevicesMatchingStates()");
219 if (mService != null && isEnabled()) {
220 try {
221 return mService.getInputDevicesMatchingConnectionStates(states);
222 } catch (RemoteException e) {
223 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
224 return new ArrayList<BluetoothDevice>();
225 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700226 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800227 if (mService == null) Log.w(TAG, "Proxy not attached to service");
228 return new ArrayList<BluetoothDevice>();
229 }
230
231 /**
232 * {@inheritDoc}
233 */
234 public int getConnectionState(BluetoothDevice device) {
235 if (DBG) log("getState(" + device + ")");
236 if (mService != null && isEnabled()
237 && isValidDevice(device)) {
238 try {
239 return mService.getInputDeviceConnectionState(device);
240 } catch (RemoteException e) {
241 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
242 return BluetoothProfile.STATE_DISCONNECTED;
243 }
244 }
245 if (mService == null) Log.w(TAG, "Proxy not attached to service");
246 return BluetoothProfile.STATE_DISCONNECTED;
247 }
248
249 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700250 * Set priority of the profile
251 *
252 * <p> The device should already be paired.
253 * Priority can be one of {@link #PRIORITY_ON} or
254 * {@link #PRIORITY_OFF},
255 *
256 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
257 * permission.
258 *
259 * @param device Paired bluetooth device
260 * @param priority
261 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800262 * @hide
263 */
264 public boolean setPriority(BluetoothDevice device, int priority) {
265 if (DBG) log("setPriority(" + device + ", " + priority + ")");
266 if (mService != null && isEnabled()
267 && isValidDevice(device)) {
268 if (priority != BluetoothProfile.PRIORITY_OFF &&
269 priority != BluetoothProfile.PRIORITY_ON) {
270 return false;
271 }
272 try {
273 return mService.setInputDevicePriority(device, priority);
274 } catch (RemoteException e) {
275 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
276 return false;
277 }
278 }
279 if (mService == null) Log.w(TAG, "Proxy not attached to service");
280 return false;
281 }
282
283 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700284 * Get the priority of the profile.
285 *
286 * <p> The priority can be any of:
287 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
288 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
289 *
290 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
291 *
292 * @param device Bluetooth device
293 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800294 * @hide
295 */
296 public int getPriority(BluetoothDevice device) {
297 if (DBG) log("getPriority(" + device + ")");
298 if (mService != null && isEnabled()
299 && isValidDevice(device)) {
300 try {
301 return mService.getInputDevicePriority(device);
302 } catch (RemoteException e) {
303 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
304 return BluetoothProfile.PRIORITY_OFF;
305 }
306 }
307 if (mService == null) Log.w(TAG, "Proxy not attached to service");
308 return BluetoothProfile.PRIORITY_OFF;
309 }
310
311 private boolean isEnabled() {
312 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
313 return false;
314 }
315
316 private boolean isValidDevice(BluetoothDevice device) {
317 if (device == null) return false;
318
319 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
320 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700321 }
322
323 private static void log(String msg) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800324 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700325 }
326}