HidService.java revision 3a04c35ba5f723ee4a6e1f1c37514691ebd1447d
1d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright/*
2d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * Copyright (C) 2012 The Android Open Source Project
3d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright *
4d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * Licensed under the Apache License, Version 2.0 (the "License");
5d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * you may not use this file except in compliance with the License.
6d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * You may obtain a copy of the License at
7d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright *
8d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright *      http://www.apache.org/licenses/LICENSE-2.0
9d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright *
10d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * Unless required by applicable law or agreed to in writing, software
11d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * distributed under the License is distributed on an "AS IS" BASIS,
12d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * See the License for the specific language governing permissions and
14d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * limitations under the License.
15d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright */
16d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
17d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightpackage com.android.bluetooth.hid;
18d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
19d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.bluetooth.BluetoothDevice;
20d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.bluetooth.BluetoothInputDevice;
21d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.bluetooth.BluetoothProfile;
22d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.bluetooth.IBluetooth;
23d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.bluetooth.IBluetoothInputDevice;
24d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.content.Intent;
25d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.content.pm.PackageManager;
26d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.os.Bundle;
27d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.os.IBinder;
28d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.os.Handler;
29d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.os.Message;
30d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.os.RemoteException;
31d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport android.os.ServiceManager;
3206936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordonimport android.provider.Settings;
3306936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordonimport android.util.Log;
3406936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordonimport com.android.bluetooth.btservice.AdapterService;
3506936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordonimport com.android.bluetooth.btservice.ProfileService;
36d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport com.android.bluetooth.Utils;
37d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport java.util.ArrayList;
38d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport java.util.Collections;
39d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport java.util.HashMap;
40d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport java.util.List;
41d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightimport java.util.Map;
42d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
43d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
44d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright/**
45d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * Provides Bluetooth Hid Host profile, as a service in
46d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * the Bluetooth application.
47d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright * @hide
48d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright */
49d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wrightpublic class HidService extends ProfileService {
50d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final boolean DBG = false;
51d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final String TAG = "HidService";
52d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
53d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private Map<BluetoothDevice, Integer> mInputDevices;
54d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private boolean mNativeAvailable;
55d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static HidService sHidService;
56d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private BluetoothDevice mTargetDevice = null;
57d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
58d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_CONNECT = 1;
59d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_DISCONNECT = 2;
60d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_CONNECT_STATE_CHANGED = 3;
61d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_GET_PROTOCOL_MODE = 4;
62d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_VIRTUAL_UNPLUG = 5;
63d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_ON_GET_PROTOCOL_MODE = 6;
64d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_SET_PROTOCOL_MODE = 7;
65d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_GET_REPORT = 8;
66d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_ON_GET_REPORT = 9;
67d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_SET_REPORT = 10;
68d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_SEND_DATA = 11;
69d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12;
70d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static final int MESSAGE_ON_HANDSHAKE = 13;
71d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
72d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    static {
73d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        classInitNative();
74d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
75d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
76d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    public String getName() {
77d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return TAG;
78d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
79d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
80d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    public IProfileServiceBinder initBinder() {
81d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return new BluetoothInputDeviceBinder(this);
82d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
83d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
84d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    protected boolean start() {
85d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mInputDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>());
86d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        initializeNative();
87d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mNativeAvailable=true;
88d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        setHidService(this);
89d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
90d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
91d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
92d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    protected boolean stop() {
93d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (DBG) log("Stopping Bluetooth HidService");
94d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
95d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
96d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
97d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    protected boolean cleanup() {
98d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (mNativeAvailable) {
99d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            cleanupNative();
100d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            mNativeAvailable=false;
101d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
102d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
103d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if(mInputDevices != null) {
104d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            mInputDevices.clear();
105d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
106d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        clearHidService();
107d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
108d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
109d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
110d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    public static synchronized HidService getHidService(){
11139efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath        if (sHidService != null && sHidService.isAvailable()) {
112d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (DBG) Log.d(TAG, "getHidService(): returning " + sHidService);
113d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return sHidService;
11439efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath        }
115d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (DBG)  {
116d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (sHidService == null) {
11739efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath                Log.d(TAG, "getHidService(): service is NULL");
118d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            } else if (!(sHidService.isAvailable())) {
119d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                Log.d(TAG,"getHidService(): service is not available");
12039efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath            }
121d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
122d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return null;
123d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
124d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
125d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static synchronized void setHidService(HidService instance) {
126d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (instance != null && instance.isAvailable()) {
127d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (DBG) Log.d(TAG, "setHidService(): set to: " + sHidService);
128d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            sHidService = instance;
129d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        } else {
130d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (DBG)  {
131d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                if (sHidService == null) {
132d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    Log.d(TAG, "setHidService(): service not available");
133d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                } else if (!sHidService.isAvailable()) {
134489fda8d476f3fc10b0251263cc69528b736257bJason Gerecke                    Log.d(TAG,"setHidService(): service is cleaning up");
135d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
136d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            }
137d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
138d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
139d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
140d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static synchronized void clearHidService() {
141d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        sHidService = null;
142d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
14306936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon
14406936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon
14506936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon    private final Handler mHandler = new Handler() {
146d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
14706936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon        @Override
14806936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon        public void handleMessage(Message msg) {
14906936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon            switch (msg.what) {
15006936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                case MESSAGE_CONNECT:
15106936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                {
15206936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    BluetoothDevice device = (BluetoothDevice) msg.obj;
15306936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    if (!connectHidNative(Utils.getByteAddress(device)) ) {
15406936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING);
15506936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
156d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        break;
157d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    }
158d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    mTargetDevice = device;
159d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
160d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    break;
161d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_DISCONNECT:
162d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
163d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = (BluetoothDevice) msg.obj;
164d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    if (!disconnectHidNative(Utils.getByteAddress(device)) ) {
165d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING);
166d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
167d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        break;
168d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    }
169d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
170d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    break;
171d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_CONNECT_STATE_CHANGED:
172d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
173d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = getDevice((byte[]) msg.obj);
17471b16e81f9cbf2e288611f32c43ea7fb4a331fcfJason Gerecke                    int halState = msg.arg1;
17571b16e81f9cbf2e288611f32c43ea7fb4a331fcfJason Gerecke                    Integer prevStateInteger = mInputDevices.get(device);
176489fda8d476f3fc10b0251263cc69528b736257bJason Gerecke                    int prevState = (prevStateInteger == null) ?
177489fda8d476f3fc10b0251263cc69528b736257bJason Gerecke                        BluetoothInputDevice.STATE_DISCONNECTED :prevStateInteger;
178489fda8d476f3fc10b0251263cc69528b736257bJason Gerecke                    if(DBG) Log.d(TAG, "MESSAGE_CONNECT_STATE_CHANGED newState:"+
179489fda8d476f3fc10b0251263cc69528b736257bJason Gerecke                        convertHalState(halState)+", prevState:"+prevState);
180489fda8d476f3fc10b0251263cc69528b736257bJason Gerecke                    if(halState == CONN_STATE_CONNECTED &&
18112d6baa9b832f16a28f048ed5ffab75a76ed9c41Jason Gerecke                       prevState == BluetoothInputDevice.STATE_DISCONNECTED &&
18212d6baa9b832f16a28f048ed5ffab75a76ed9c41Jason Gerecke                       (!okToConnect(device))) {
18378f97b3263053c388080a738b56499139517c3b6Vladislav Kaznacheev                        if (DBG) Log.d(TAG,"Incoming HID connection rejected");
18478f97b3263053c388080a738b56499139517c3b6Vladislav Kaznacheev                        disconnectHidNative(Utils.getByteAddress(device));
18578f97b3263053c388080a738b56499139517c3b6Vladislav Kaznacheev                    } else {
18678f97b3263053c388080a738b56499139517c3b6Vladislav Kaznacheev                        broadcastConnectionState(device, convertHalState(halState));
187d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    }
18806936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    if (halState != CONN_STATE_CONNECTING) {
18906936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                        mTargetDevice = null;
19006936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    }
19106936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    else {
19206936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                        // CONN_STATE_CONNECTING is received only during
19306936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                        // local initiated connection.
19406936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                        mTargetDevice = device;
19506936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    }
19606936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                }
19706936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    break;
19806936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                case MESSAGE_GET_PROTOCOL_MODE:
19906936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                {
20006936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    BluetoothDevice device = (BluetoothDevice) msg.obj;
20106936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    if(!getProtocolModeNative(Utils.getByteAddress(device)) ) {
20206936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                        Log.e(TAG, "Error: get protocol mode native returns false");
20306936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                    }
20406936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                }
20506936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                break;
20606936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon
20706936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                case MESSAGE_ON_GET_PROTOCOL_MODE:
20806936feb07bf6fbef262e4adebeb8e53910d8cf4Santos Cordon                {
209d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = getDevice((byte[]) msg.obj);
210d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    int protocolMode = msg.arg1;
211d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    broadcastProtocolMode(device, protocolMode);
212d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
213d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                break;
214d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_VIRTUAL_UNPLUG:
215d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
216d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = (BluetoothDevice) msg.obj;
217d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    if(!virtualUnPlugNative(Utils.getByteAddress(device))) {
218d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        Log.e(TAG, "Error: virtual unplug native returns false");
219d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    }
220d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
22139efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath                break;
222d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_SET_PROTOCOL_MODE:
223d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
224d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = (BluetoothDevice) msg.obj;
22539efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath                    byte protocolMode = (byte) msg.arg1;
226d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    log("sending set protocol mode(" + protocolMode + ")");
227d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    if(!setProtocolModeNative(Utils.getByteAddress(device), protocolMode)) {
228d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        Log.e(TAG, "Error: set protocol mode native returns false");
229d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    }
230d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
231d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                break;
232d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_GET_REPORT:
233d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
234d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = (BluetoothDevice) msg.obj;
235d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    Bundle data = msg.getData();
236d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE);
237d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    byte reportId = data.getByte(BluetoothInputDevice.EXTRA_REPORT_ID);
238d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE);
239d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    if(!getReportNative(Utils.getByteAddress(device), reportType, reportId, bufferSize)) {
240d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        Log.e(TAG, "Error: get report native returns false");
241d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    }
242d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
243d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                break;
244d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_ON_GET_REPORT:
245d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
246d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = getDevice((byte[])msg.obj);
247d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    Bundle data = msg.getData();
248d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    byte[] report = data.getByteArray(BluetoothInputDevice.EXTRA_REPORT);
249d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE);
250d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    broadcastReport(device, report, bufferSize);
251d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
252d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                break;
253d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_ON_HANDSHAKE:
254d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
255d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = getDevice((byte[])msg.obj);
256d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    int status = msg.arg1;
257d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    broadcastHandshake(device, status);
258d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
259d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                break;
260d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_SET_REPORT:
261d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
262d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = (BluetoothDevice) msg.obj;
263d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    Bundle data = msg.getData();
264d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE);
265d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    String report = data.getString(BluetoothInputDevice.EXTRA_REPORT);
266d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    if(!setReportNative(Utils.getByteAddress(device), reportType, report)) {
267d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        Log.e(TAG, "Error: set report native returns false");
268d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    }
269d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
270d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                break;
271d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_SEND_DATA:
272d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
273d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = (BluetoothDevice) msg.obj;
274d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    Bundle data = msg.getData();
275d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    String report = data.getString(BluetoothInputDevice.EXTRA_REPORT);
276d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    if(!sendDataNative(Utils.getByteAddress(device), report)) {
277d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                        Log.e(TAG, "Error: send data native returns false");
278d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    }
279d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
280d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                break;
281d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                case MESSAGE_ON_VIRTUAL_UNPLUG:
282d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                {
283d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    BluetoothDevice device = getDevice((byte[]) msg.obj);
284d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    int status = msg.arg1;
285d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    broadcastVirtualUnplugStatus(device, status);
286d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
287d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                break;
288d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            }
289d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
290d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    };
291d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
292d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    /**
293d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright     * Handlers for incoming service calls
294d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright     */
295d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static class BluetoothInputDeviceBinder extends IBluetoothInputDevice.Stub implements IProfileServiceBinder{
296d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        private HidService mService;
297d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public BluetoothInputDeviceBinder(HidService svc) {
298d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            mService = svc;
299d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
300d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
301d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean cleanup() {
302d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            mService = null;
303d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return true;
304d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
305d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
306d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        private HidService getService() {
307d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (!Utils.checkCaller()) {
308d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                Log.w(TAG,"InputDevice call not allowed for non-active user");
309d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                return null;
310d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            }
311d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
312d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (mService  != null && mService.isAvailable()) {
313d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                return mService;
314d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            }
315d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return null;
316d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
317d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
318d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean connect(BluetoothDevice device) {
319d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
320d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
321d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.connect(device);
322d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
323d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
324d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean disconnect(BluetoothDevice device) {
325d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
326d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
327d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.disconnect(device);
328d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
329d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
330d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public int getConnectionState(BluetoothDevice device) {
331d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
332d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return BluetoothInputDevice.STATE_DISCONNECTED;
333d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.getConnectionState(device);
334d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
335d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
336d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public List<BluetoothDevice> getConnectedDevices() {
337d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return getDevicesMatchingConnectionStates(
338d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    new int[] {BluetoothProfile.STATE_CONNECTED});
339d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
340d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
341d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
342d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
343d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return new ArrayList<BluetoothDevice>(0);
344d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.getDevicesMatchingConnectionStates(states);
345d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
346d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
347d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean setPriority(BluetoothDevice device, int priority) {
348d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
349d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
350d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.setPriority(device, priority);
3516ca70efdaef8c07e91692101c7a3ae35dc1e0cbbChih-Hung Hsieh        }
352d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
353d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public int getPriority(BluetoothDevice device) {
354d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
355d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
356d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.getPriority(device);
357d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
358d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
359d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        /* The following APIs regarding test app for compliance */
360d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean getProtocolMode(BluetoothDevice device) {
361d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
362d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
363d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.getProtocolMode(device);
364d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
365d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
366d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean virtualUnplug(BluetoothDevice device) {
367d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
368d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
369d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.virtualUnplug(device);
370d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
371d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
372d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
373d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
374d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
375d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.setProtocolMode(device, protocolMode);
376d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
377d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
378d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
379d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
380d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
381d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.getReport(device, reportType, reportId, bufferSize) ;
382d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
383d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
384d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean setReport(BluetoothDevice device, byte reportType, String report) {
385d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
386d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
387d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.setReport(device, reportType, report);
388d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
389d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
390d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        public boolean sendData(BluetoothDevice device, String report) {
391d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            HidService service = getService();
392d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            if (service == null) return false;
393d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return service.sendData(device, report);
394d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
395d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    };
396d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
397d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    //APIs
398d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    boolean connect(BluetoothDevice device) {
399d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
400d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (getConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED) {
401d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            Log.e(TAG, "Hid Device not disconnected: " + device);
402d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return false;
403d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
404d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (getPriority(device) == BluetoothInputDevice.PRIORITY_OFF) {
405d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            Log.e(TAG, "Hid Device PRIORITY_OFF: " + device);
406d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return false;
407d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
408d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
409d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device);
410d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
411d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
412d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
413d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
414d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    boolean disconnect(BluetoothDevice device) {
415d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
416d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT,device);
417d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
418d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
419d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
420d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
421d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    int getConnectionState(BluetoothDevice device) {
422d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (mInputDevices.get(device) == null) {
423d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return BluetoothInputDevice.STATE_DISCONNECTED;
424d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
425d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return mInputDevices.get(device);
426d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
427d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
428d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
429d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
430d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
431d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
432d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        for (BluetoothDevice device: mInputDevices.keySet()) {
433d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            int inputDeviceState = getConnectionState(device);
434d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            for (int state : states) {
435d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                if (state == inputDeviceState) {
436d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    inputDevices.add(device);
437d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                    break;
438d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                }
439d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            }
440d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
441d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return inputDevices;
442d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
443d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
444d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    public boolean setPriority(BluetoothDevice device, int priority) {
445d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
446d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                       "Need BLUETOOTH_ADMIN permission");
447d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Settings.Global.putInt(getContentResolver(),
448d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            Settings.Global.getBluetoothInputDevicePriorityKey(device.getAddress()),
449d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            priority);
450d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority);
451d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
452d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
453d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
454d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    public  int getPriority(BluetoothDevice device) {
455d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
456d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                       "Need BLUETOOTH_ADMIN permission");
457d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        int priority = Settings.Global.getInt(getContentResolver(),
458d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            Settings.Global.getBluetoothInputDevicePriorityKey(device.getAddress()),
459d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            BluetoothProfile.PRIORITY_UNDEFINED);
460d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return priority;
461d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
462d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
463d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    /* The following APIs regarding test app for compliance */
464d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    boolean getProtocolMode(BluetoothDevice device) {
465d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
466d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                       "Need BLUETOOTH_ADMIN permission");
467d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        int state = this.getConnectionState(device);
468d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (state != BluetoothInputDevice.STATE_CONNECTED) {
469d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return false;
470d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
471d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_GET_PROTOCOL_MODE,device);
472d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
473d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
474d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        /* String objectPath = getObjectPathFromAddress(device.getAddress());
475d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return getProtocolModeInputDeviceNative(objectPath);*/
476d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
477d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
478d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    boolean virtualUnplug(BluetoothDevice device) {
479d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
480d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                       "Need BLUETOOTH_ADMIN permission");
481d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        int state = this.getConnectionState(device);
482d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (state != BluetoothInputDevice.STATE_CONNECTED) {
483d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return false;
484d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
485d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_VIRTUAL_UNPLUG,device);
486d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
487d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
488d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
489d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
490d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
491d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
492d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                       "Need BLUETOOTH_ADMIN permission");
493d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        int state = this.getConnectionState(device);
494d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (state != BluetoothInputDevice.STATE_CONNECTED) {
495d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return false;
496d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
497d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL_MODE);
498d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = device;
499d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.arg1 = protocolMode;
500d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
501d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true ;
502d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
503d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
504d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
505d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
506d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                       "Need BLUETOOTH_ADMIN permission");
50739efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath        int state = this.getConnectionState(device);
508d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (state != BluetoothInputDevice.STATE_CONNECTED) {
509d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return false;
510d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
511d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT);
512d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = device;
513d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Bundle data = new Bundle();
514d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType);
515d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        data.putByte(BluetoothInputDevice.EXTRA_REPORT_ID, reportId);
516d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, bufferSize);
517d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.setData(data);
518d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
519d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true ;
520d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
521d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
522d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    boolean setReport(BluetoothDevice device, byte reportType, String report) {
523d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
524d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                                   "Need BLUETOOTH_ADMIN permission");
525d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        int state = this.getConnectionState(device);
526d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (state != BluetoothInputDevice.STATE_CONNECTED) {
527d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return false;
528d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
529d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT);
530d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = device;
531d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Bundle data = new Bundle();
532d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType);
533d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        data.putString(BluetoothInputDevice.EXTRA_REPORT, report);
534d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.setData(data);
535d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
536d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true ;
537d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
538d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
539d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
54039efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath    boolean sendData(BluetoothDevice device, String report) {
541d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
542d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                                   "Need BLUETOOTH_ADMIN permission");
543d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        int state = this.getConnectionState(device);
5440faaa0bd7aa5dadea7c365fbb1f186da6eb097efDmitry Torokhov        if (state != BluetoothInputDevice.STATE_CONNECTED) {
5450faaa0bd7aa5dadea7c365fbb1f186da6eb097efDmitry Torokhov            return false;
5460faaa0bd7aa5dadea7c365fbb1f186da6eb097efDmitry Torokhov        }
547d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
548d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return sendDataNative(Utils.getByteAddress(device), report);
549d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        /*Message msg = mHandler.obtainMessage(MESSAGE_SEND_DATA);
550d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = device;
551d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Bundle data = new Bundle();
552d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        data.putString(BluetoothInputDevice.EXTRA_REPORT, report);
553d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.setData(data);
554d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
555d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true ;*/
556d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
5570faaa0bd7aa5dadea7c365fbb1f186da6eb097efDmitry Torokhov
5580faaa0bd7aa5dadea7c365fbb1f186da6eb097efDmitry Torokhov    private void onGetProtocolMode(byte[] address, int mode) {
5590faaa0bd7aa5dadea7c365fbb1f186da6eb097efDmitry Torokhov        Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_PROTOCOL_MODE);
560d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = address;
561d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.arg1 = mode;
562d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
563d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
564d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
565d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private void onGetReport(byte[] address, byte[] report, int rpt_size) {
566d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_REPORT);
567d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = address;
568d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Bundle data = new Bundle();
569d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        data.putByteArray(BluetoothInputDevice.EXTRA_REPORT, report);
570d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, rpt_size);
571d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.setData(data);
572d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
573d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
574d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
575d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private void onHandshake(byte[] address, int status) {
576d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_ON_HANDSHAKE);
577d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = address;
578d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.arg1 = status;
579d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
580d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
581d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
58239efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath    private void onVirtualUnplug(byte[] address, int status) {
583d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Message msg = mHandler.obtainMessage(MESSAGE_ON_VIRTUAL_UNPLUG);
584d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = address;
585d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.arg1 = status;
586d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
587d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
588d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
589d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private void onConnectStateChanged(byte[] address, int state) {
59039efe3e5bf6282a4851e0eb3b938060c8f7790aeNarayan Kamath        Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED);
591d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.obj = address;
592d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        msg.arg1 = state;
593d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mHandler.sendMessage(msg);
594d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
595d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
596d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    // This method does not check for error conditon (newState == prevState)
597d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private void broadcastConnectionState(BluetoothDevice device, int newState) {
598d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Integer prevStateInteger = mInputDevices.get(device);
599d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        int prevState = (prevStateInteger == null) ? BluetoothInputDevice.STATE_DISCONNECTED :
600d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                                     prevStateInteger;
601d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (prevState == newState) {
602d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            Log.w(TAG, "no state change: " + newState);
603d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return;
604d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
605d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        mInputDevices.put(device, newState);
606d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
607d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        /* Notifying the connection state change of the profile before sending the intent for
608d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright           connection state change, as it was causing a race condition, with the UI not being
609d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright           updated with the correct connection state. */
610d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        log("Connection state " + device + ": " + prevState + "->" + newState);
611d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        notifyProfileConnectionStateChanged(device, BluetoothProfile.INPUT_DEVICE,
612d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                                            newState, prevState);
613d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
614d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
615d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
616d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
617d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
618d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        sendBroadcast(intent, BLUETOOTH_PERM);
619d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
620d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
621d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private void broadcastHandshake(BluetoothDevice device, int status) {
622d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Intent intent = new Intent(BluetoothInputDevice.ACTION_HANDSHAKE);
623d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
624d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothInputDevice.EXTRA_STATUS, status);
625d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
626d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        sendBroadcast(intent, BLUETOOTH_PERM);
627d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
628d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
629d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private void broadcastProtocolMode(BluetoothDevice device, int protocolMode) {
630d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Intent intent = new Intent(BluetoothInputDevice.ACTION_PROTOCOL_MODE_CHANGED);
631d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
632d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothInputDevice.EXTRA_PROTOCOL_MODE, protocolMode);
633d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
634d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        sendBroadcast(intent, BLUETOOTH_PERM);
635d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if (DBG) log("Protocol Mode (" + device + "): " + protocolMode);
636d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
637d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
638d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private void broadcastReport(BluetoothDevice device, byte[] report, int rpt_size) {
639d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Intent intent = new Intent(BluetoothInputDevice.ACTION_REPORT);
640d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
641d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothInputDevice.EXTRA_REPORT, report);
642d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, rpt_size);
643d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
644d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        sendBroadcast(intent, BLUETOOTH_PERM);
645d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
646d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
647d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private void broadcastVirtualUnplugStatus(BluetoothDevice device, int status) {
648d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        Intent intent = new Intent(BluetoothInputDevice.ACTION_VIRTUAL_UNPLUG_STATUS);
649d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
650d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.putExtra(BluetoothInputDevice.EXTRA_VIRTUAL_UNPLUG_STATUS, status);
651d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
652d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        sendBroadcast(intent, BLUETOOTH_PERM);
653d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
654d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
655d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private boolean okToConnect(BluetoothDevice device) {
656d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        AdapterService adapterService = AdapterService.getAdapterService();
657d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        //check if it is inbound connection in Quiet mode, priority and Bond status
658d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        //to decide if its ok to allow this connection
659d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        if((adapterService == null)||
660d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright           ((adapterService.isQuietModeEnabled()) &&(mTargetDevice == null)) ||
661d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright           (BluetoothProfile.PRIORITY_OFF == getPriority(device)) ||
662d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright           (device.getBondState() == BluetoothDevice.BOND_NONE))
663d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            return false;
664d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
665d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        return true;
666d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
667d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private static int convertHalState(int halState) {
668d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        switch (halState) {
669d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            case CONN_STATE_CONNECTED:
670d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                return BluetoothProfile.STATE_CONNECTED;
671d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            case CONN_STATE_CONNECTING:
672d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                return BluetoothProfile.STATE_CONNECTING;
673d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            case CONN_STATE_DISCONNECTED:
674d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                return BluetoothProfile.STATE_DISCONNECTED;
675d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            case CONN_STATE_DISCONNECTING:
676d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                return BluetoothProfile.STATE_DISCONNECTING;
677d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright            default:
678d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                Log.e(TAG, "bad hid connection state: " + halState);
679d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright                return BluetoothProfile.STATE_DISCONNECTED;
680d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright        }
681d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    }
682d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
683d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    // Constants matching Hal header file bt_hh.h
684d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    // bthh_connection_state_t
685d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private final static int CONN_STATE_CONNECTED = 0;
686d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private final static int CONN_STATE_CONNECTING = 1;
687d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private final static int CONN_STATE_DISCONNECTED = 2;
688d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private final static int CONN_STATE_DISCONNECTING = 3;
689d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright
690d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native static void classInitNative();
691d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native void initializeNative();
692d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native void cleanupNative();
693d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native boolean connectHidNative(byte[] btAddress);
694d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native boolean disconnectHidNative(byte[] btAddress);
695d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native boolean getProtocolModeNative(byte[] btAddress);
696d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native boolean virtualUnPlugNative(byte[] btAddress);
697d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native boolean setProtocolModeNative(byte[] btAddress, byte protocolMode);
698d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native boolean getReportNative(byte[]btAddress, byte reportType, byte reportId, int bufferSize);
699d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native boolean setReportNative(byte[] btAddress, byte reportType, String report);
700d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright    private native boolean sendDataNative(byte[] btAddress, String report);
701d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright}
702d02c5b6aace05d9fd938e2d03705ac4f60f8da19Michael Wright