1066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood/*
2066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * Copyright (C) 2014 The Android Open Source Project
3066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood *
4066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
5066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * you may not use this file except in compliance with the License.
6066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * You may obtain a copy of the License at
7066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood *
8066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
9066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood *
10066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * Unless required by applicable law or agreed to in writing, software
11066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
12066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * See the License for the specific language governing permissions and
14066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * limitations under the License.
15066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood */
16066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
17066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpackage com.android.bluetooth.avrcp;
18066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
19066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothAdapter;
20066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothAvrcpController;
21066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothDevice;
22066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothProfile;
23066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.IBluetoothAvrcpController;
24066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.content.Intent;
25066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.os.Handler;
26066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.os.HandlerThread;
27066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.os.Looper;
28066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.os.Message;
29066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.util.Log;
30066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
31066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport com.android.bluetooth.btservice.ProfileService;
32066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport com.android.bluetooth.Utils;
33066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
34066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport java.util.ArrayList;
35066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport java.util.List;
36066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport java.util.HashMap;
37066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
38066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood/**
39066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * Provides Bluetooth AVRCP Controller profile, as a service in the Bluetooth application.
40066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood * @hide
41066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood */
42066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpublic class AvrcpControllerService extends ProfileService {
43066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private static final boolean DBG = false;
44066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private static final String TAG = "AvrcpControllerService";
45066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
46066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private static final int MESSAGE_SEND_PASS_THROUGH_CMD = 1;
47066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
48066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private AvrcpMessageHandler mHandler;
49066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private static AvrcpControllerService sAvrcpControllerService;
50066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
51066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private final ArrayList<BluetoothDevice> mConnectedDevices
52066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            = new ArrayList<BluetoothDevice>();
53066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
54066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    static {
55066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        classInitNative();
56066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
57066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
58066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public AvrcpControllerService() {
59066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        initNative();
60066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
61066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
62066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    protected String getName() {
63066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return TAG;
64066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
65066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
66066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    protected IProfileServiceBinder initBinder() {
67066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return new BluetoothAvrcpControllerBinder(this);
68066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
69066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
70066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    protected boolean start() {
71066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
72066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        thread.start();
73066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        Looper looper = thread.getLooper();
74066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        mHandler = new AvrcpMessageHandler(looper);
75066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
76066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        setAvrcpControllerService(this);
77066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return true;
78066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
79066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
80066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    protected boolean stop() {
81066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return true;
82066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
83066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
84066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    protected boolean cleanup() {
85066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        mHandler.removeCallbacksAndMessages(null);
86066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        Looper looper = mHandler.getLooper();
87066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        if (looper != null) {
88066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            looper.quit();
89066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
90066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
91066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        clearAvrcpControllerService();
92066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
93066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        cleanupNative();
94066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
95066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return true;
96066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
97066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
98066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    //API Methods
99066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
100066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public static synchronized AvrcpControllerService getAvrcpControllerService(){
101066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        if (sAvrcpControllerService != null && sAvrcpControllerService.isAvailable()) {
102066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (DBG) Log.d(TAG, "getAvrcpControllerService(): returning "
103066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                    + sAvrcpControllerService);
104066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            return sAvrcpControllerService;
105066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
106066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        if (DBG)  {
107066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (sAvrcpControllerService == null) {
108066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                Log.d(TAG, "getAvrcpControllerService(): service is NULL");
109066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            } else if (!(sAvrcpControllerService.isAvailable())) {
110066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                Log.d(TAG,"getAvrcpControllerService(): service is not available");
111066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            }
112066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
113066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return null;
114066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
115066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
116066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private static synchronized void setAvrcpControllerService(AvrcpControllerService instance) {
117066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        if (instance != null && instance.isAvailable()) {
118066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (DBG) Log.d(TAG, "setAvrcpControllerService(): set to: " + sAvrcpControllerService);
119066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            sAvrcpControllerService = instance;
120066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        } else {
121066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (DBG)  {
122066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                if (sAvrcpControllerService == null) {
123066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                    Log.d(TAG, "setAvrcpControllerService(): service not available");
124066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                } else if (!sAvrcpControllerService.isAvailable()) {
125066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                    Log.d(TAG,"setAvrcpControllerService(): service is cleaning up");
126066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                }
127066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            }
128066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
129066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
130066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
131066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private static synchronized void clearAvrcpControllerService() {
132066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        sAvrcpControllerService = null;
133066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
134066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
135066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public List<BluetoothDevice> getConnectedDevices() {
136066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
137066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return mConnectedDevices;
138066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
139066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
140066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
141066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
142066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        for (int i = 0; i < states.length; i++) {
143066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (states[i] == BluetoothProfile.STATE_CONNECTED) {
144066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                return mConnectedDevices;
145066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            }
146066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
147066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return new ArrayList<BluetoothDevice>();
148066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
149066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
150066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    int getConnectionState(BluetoothDevice device) {
151066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
152066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return (mConnectedDevices.contains(device) ? BluetoothProfile.STATE_CONNECTED
153066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                                                : BluetoothProfile.STATE_DISCONNECTED);
154066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
155066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
156066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
157066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        if (DBG) Log.d(TAG, "sendPassThroughCmd");
158066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        Log.v(TAG, "keyCode: " + keyCode + " keyState: " + keyState);
159066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        if (device == null) {
160066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            throw new NullPointerException("device == null");
161066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
162066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
163066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        Message msg = mHandler.obtainMessage(MESSAGE_SEND_PASS_THROUGH_CMD,
164066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                keyCode, keyState, device);
165066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        mHandler.sendMessage(msg);
166066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
167066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
168066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    //Binder object: Must be static class or memory leak may occur
169066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private static class BluetoothAvrcpControllerBinder extends IBluetoothAvrcpController.Stub
170066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        implements IProfileServiceBinder {
171066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        private AvrcpControllerService mService;
172066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
173066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        private AvrcpControllerService getService() {
174066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (!Utils.checkCaller()) {
175066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                Log.w(TAG,"AVRCP call not allowed for non-active user");
176066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                return null;
177066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            }
178066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
179066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (mService != null && mService.isAvailable()) {
180066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                return mService;
181066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            }
182066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            return null;
183066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
184066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
185066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        BluetoothAvrcpControllerBinder(AvrcpControllerService svc) {
186066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            mService = svc;
187066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
188066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
189066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        public boolean cleanup()  {
190066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            mService = null;
191066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            return true;
192066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
193066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
194066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        public List<BluetoothDevice> getConnectedDevices() {
195066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            AvrcpControllerService service = getService();
196066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (service == null) return new ArrayList<BluetoothDevice>(0);
197066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            return service.getConnectedDevices();
198066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
199066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
200066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
201066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            AvrcpControllerService service = getService();
202066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (service == null) return new ArrayList<BluetoothDevice>(0);
203066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            return service.getDevicesMatchingConnectionStates(states);
204066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
205066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
206066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        public int getConnectionState(BluetoothDevice device) {
207066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            AvrcpControllerService service = getService();
208066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
209066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            return service.getConnectionState(device);
210066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
211066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
212066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
213066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            Log.v(TAG,"Binder Call: sendPassThroughCmd");
214066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            AvrcpControllerService service = getService();
215066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            if (service == null) return;
216066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            service.sendPassThroughCmd(device, keyCode, keyState);
217066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
218066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    };
219066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
220066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    /** Handles Avrcp messages. */
221066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private final class AvrcpMessageHandler extends Handler {
222066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        private AvrcpMessageHandler(Looper looper) {
223066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            super(looper);
224066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
225066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
226066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        @Override
227066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        public void handleMessage(Message msg) {
228066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            switch (msg.what) {
229066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            case MESSAGE_SEND_PASS_THROUGH_CMD:
230066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                if (DBG) Log.v(TAG, "MESSAGE_SEND_PASS_THROUGH_CMD");
231066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                BluetoothDevice device = (BluetoothDevice)msg.obj;
232066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                sendPassThroughCommandNative(getByteAddress(device), msg.arg1, msg.arg2);
233066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                break;
234066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            }
235066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
236066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
237066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
238066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private void onConnectionStateChanged(boolean connected, byte[] address) {
239066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
240066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            (Utils.getAddressStringFromByte(address));
241066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        Log.d(TAG, "onConnectionStateChanged " + connected + " " + device);
242066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        Intent intent = new Intent(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED);
243066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        int oldState = (mConnectedDevices.contains(device) ? BluetoothProfile.STATE_CONNECTED
244066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                                                        : BluetoothProfile.STATE_DISCONNECTED);
245066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        int newState = (connected ? BluetoothProfile.STATE_CONNECTED
246066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                                  : BluetoothProfile.STATE_DISCONNECTED);
247066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, oldState);
248066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
249066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
250066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood//        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
251066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
252066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        if (connected && oldState == BluetoothProfile.STATE_DISCONNECTED) {
253066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            mConnectedDevices.add(device);
254066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        } else if (!connected && oldState == BluetoothProfile.STATE_CONNECTED) {
255066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            mConnectedDevices.remove(device);
256066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        }
257066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
258066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
259066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private void handlePassthroughRsp(int id, int keyState) {
260066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        Log.d(TAG, "passthrough response received as: key: "
261066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood                                + id + " state: " + keyState);
262066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
263066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
264066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private byte[] getByteAddress(BluetoothDevice device) {
265066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood        return Utils.getBytesFromAddress(device.getAddress());
266066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    }
267066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood
268066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private native static void classInitNative();
269066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private native void initNative();
270066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private native void cleanupNative();
271066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    private native boolean sendPassThroughCommandNative(byte[] address, int keyCode, int keyState);
272066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood}
273