blob: 1a9e011ad7fe14cb9ef75277b8f54366cfe81a57 [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 Ganesh9bb27512011-11-28 09:59:08 -0800121 /*package*/ void close() {
122 mServiceListener = null;
123 }
124
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800125 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700126 * Initiate connection to a profile of the remote bluetooth device.
127 *
128 * <p> The system supports connection to multiple input devices.
129 *
130 * <p> This API returns false in scenarios like the profile on the
131 * device is already connected or Bluetooth is not turned on.
132 * When this API returns true, it is guaranteed that
133 * connection state intent for the profile will be broadcasted with
134 * the state. Users can get the connection state of the profile
135 * from this intent.
136 *
137 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
138 * permission.
139 *
140 * @param device Remote Bluetooth Device
141 * @return false on immediate error,
142 * true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800143 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700144 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800145 public boolean connect(BluetoothDevice device) {
146 if (DBG) log("connect(" + device + ")");
147 if (mService != null && isEnabled() &&
148 isValidDevice(device)) {
149 try {
150 return mService.connectInputDevice(device);
151 } catch (RemoteException e) {
152 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
153 return false;
154 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700155 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800156 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700157 return false;
158 }
159
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800160 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700161 * Initiate disconnection from a profile
162 *
163 * <p> This API will return false in scenarios like the profile on the
164 * Bluetooth device is not in connected state etc. When this API returns,
165 * true, it is guaranteed that the connection state change
166 * intent will be broadcasted with the state. Users can get the
167 * disconnection state of the profile from this intent.
168 *
169 * <p> If the disconnection is initiated by a remote device, the state
170 * will transition from {@link #STATE_CONNECTED} to
171 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
172 * host (local) device the state will transition from
173 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
174 * state {@link #STATE_DISCONNECTED}. The transition to
175 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
176 * two scenarios.
177 *
178 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
179 * permission.
180 *
181 * @param device Remote Bluetooth Device
182 * @return false on immediate error,
183 * true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700184 * @hide
185 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800186 public boolean disconnect(BluetoothDevice device) {
187 if (DBG) log("disconnect(" + device + ")");
188 if (mService != null && isEnabled() &&
189 isValidDevice(device)) {
190 try {
191 return mService.disconnectInputDevice(device);
192 } catch (RemoteException e) {
193 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
194 return false;
195 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700196 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800197 if (mService == null) Log.w(TAG, "Proxy not attached to service");
198 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700199 }
200
201 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800202 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700203 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800204 public List<BluetoothDevice> getConnectedDevices() {
205 if (DBG) log("getConnectedDevices()");
206 if (mService != null && isEnabled()) {
207 try {
208 return mService.getConnectedInputDevices();
209 } catch (RemoteException e) {
210 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
211 return new ArrayList<BluetoothDevice>();
212 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700213 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800214 if (mService == null) Log.w(TAG, "Proxy not attached to service");
215 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700216 }
217
218 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800219 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700220 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800221 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
222 if (DBG) log("getDevicesMatchingStates()");
223 if (mService != null && isEnabled()) {
224 try {
225 return mService.getInputDevicesMatchingConnectionStates(states);
226 } catch (RemoteException e) {
227 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
228 return new ArrayList<BluetoothDevice>();
229 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700230 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800231 if (mService == null) Log.w(TAG, "Proxy not attached to service");
232 return new ArrayList<BluetoothDevice>();
233 }
234
235 /**
236 * {@inheritDoc}
237 */
238 public int getConnectionState(BluetoothDevice device) {
239 if (DBG) log("getState(" + device + ")");
240 if (mService != null && isEnabled()
241 && isValidDevice(device)) {
242 try {
243 return mService.getInputDeviceConnectionState(device);
244 } catch (RemoteException e) {
245 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
246 return BluetoothProfile.STATE_DISCONNECTED;
247 }
248 }
249 if (mService == null) Log.w(TAG, "Proxy not attached to service");
250 return BluetoothProfile.STATE_DISCONNECTED;
251 }
252
253 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700254 * Set priority of the profile
255 *
256 * <p> The device should already be paired.
257 * Priority can be one of {@link #PRIORITY_ON} or
258 * {@link #PRIORITY_OFF},
259 *
260 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
261 * permission.
262 *
263 * @param device Paired bluetooth device
264 * @param priority
265 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800266 * @hide
267 */
268 public boolean setPriority(BluetoothDevice device, int priority) {
269 if (DBG) log("setPriority(" + device + ", " + priority + ")");
270 if (mService != null && isEnabled()
271 && isValidDevice(device)) {
272 if (priority != BluetoothProfile.PRIORITY_OFF &&
273 priority != BluetoothProfile.PRIORITY_ON) {
274 return false;
275 }
276 try {
277 return mService.setInputDevicePriority(device, priority);
278 } catch (RemoteException e) {
279 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
280 return false;
281 }
282 }
283 if (mService == null) Log.w(TAG, "Proxy not attached to service");
284 return false;
285 }
286
287 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700288 * Get the priority of the profile.
289 *
290 * <p> The priority can be any of:
291 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
292 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
293 *
294 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
295 *
296 * @param device Bluetooth device
297 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800298 * @hide
299 */
300 public int getPriority(BluetoothDevice device) {
301 if (DBG) log("getPriority(" + device + ")");
302 if (mService != null && isEnabled()
303 && isValidDevice(device)) {
304 try {
305 return mService.getInputDevicePriority(device);
306 } catch (RemoteException e) {
307 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
308 return BluetoothProfile.PRIORITY_OFF;
309 }
310 }
311 if (mService == null) Log.w(TAG, "Proxy not attached to service");
312 return BluetoothProfile.PRIORITY_OFF;
313 }
314
315 private boolean isEnabled() {
316 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
317 return false;
318 }
319
320 private boolean isValidDevice(BluetoothDevice device) {
321 if (device == null) return false;
322
323 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
324 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700325 }
326
327 private static void log(String msg) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800328 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700329 }
330}