• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.avrcp;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothAvrcpController;
21 import android.bluetooth.BluetoothDevice;
22 import android.bluetooth.BluetoothProfile;
23 import android.bluetooth.IBluetoothAvrcpController;
24 import android.content.Intent;
25 import android.os.Handler;
26 import android.os.HandlerThread;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.util.Log;
30 
31 import com.android.bluetooth.btservice.ProfileService;
32 import com.android.bluetooth.Utils;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.HashMap;
37 
38 /**
39  * Provides Bluetooth AVRCP Controller profile, as a service in the Bluetooth application.
40  * @hide
41  */
42 public class AvrcpControllerService extends ProfileService {
43     private static final boolean DBG = false;
44     private static final String TAG = "AvrcpControllerService";
45 
46     private static final int MESSAGE_SEND_PASS_THROUGH_CMD = 1;
47 
48     private AvrcpMessageHandler mHandler;
49     private static AvrcpControllerService sAvrcpControllerService;
50 
51     private final ArrayList<BluetoothDevice> mConnectedDevices
52             = new ArrayList<BluetoothDevice>();
53 
54     static {
classInitNative()55         classInitNative();
56     }
57 
AvrcpControllerService()58     public AvrcpControllerService() {
59         initNative();
60     }
61 
getName()62     protected String getName() {
63         return TAG;
64     }
65 
initBinder()66     protected IProfileServiceBinder initBinder() {
67         return new BluetoothAvrcpControllerBinder(this);
68     }
69 
start()70     protected boolean start() {
71         HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
72         thread.start();
73         Looper looper = thread.getLooper();
74         mHandler = new AvrcpMessageHandler(looper);
75 
76         setAvrcpControllerService(this);
77         return true;
78     }
79 
stop()80     protected boolean stop() {
81         return true;
82     }
83 
cleanup()84     protected boolean cleanup() {
85         if (mHandler != null) {
86             mHandler.removeCallbacksAndMessages(null);
87             Looper looper = mHandler.getLooper();
88             if (looper != null) looper.quit();
89         }
90 
91         clearAvrcpControllerService();
92         cleanupNative();
93 
94         return true;
95     }
96 
97     //API Methods
98 
getAvrcpControllerService()99     public static synchronized AvrcpControllerService getAvrcpControllerService(){
100         if (sAvrcpControllerService != null && sAvrcpControllerService.isAvailable()) {
101             if (DBG) Log.d(TAG, "getAvrcpControllerService(): returning "
102                     + sAvrcpControllerService);
103             return sAvrcpControllerService;
104         }
105         if (DBG)  {
106             if (sAvrcpControllerService == null) {
107                 Log.d(TAG, "getAvrcpControllerService(): service is NULL");
108             } else if (!(sAvrcpControllerService.isAvailable())) {
109                 Log.d(TAG,"getAvrcpControllerService(): service is not available");
110             }
111         }
112         return null;
113     }
114 
setAvrcpControllerService(AvrcpControllerService instance)115     private static synchronized void setAvrcpControllerService(AvrcpControllerService instance) {
116         if (instance != null && instance.isAvailable()) {
117             if (DBG) Log.d(TAG, "setAvrcpControllerService(): set to: " + sAvrcpControllerService);
118             sAvrcpControllerService = instance;
119         } else {
120             if (DBG)  {
121                 if (sAvrcpControllerService == null) {
122                     Log.d(TAG, "setAvrcpControllerService(): service not available");
123                 } else if (!sAvrcpControllerService.isAvailable()) {
124                     Log.d(TAG,"setAvrcpControllerService(): service is cleaning up");
125                 }
126             }
127         }
128     }
129 
clearAvrcpControllerService()130     private static synchronized void clearAvrcpControllerService() {
131         sAvrcpControllerService = null;
132     }
133 
getConnectedDevices()134     public List<BluetoothDevice> getConnectedDevices() {
135         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
136         return mConnectedDevices;
137     }
138 
getDevicesMatchingConnectionStates(int[] states)139     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
140         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
141         for (int i = 0; i < states.length; i++) {
142             if (states[i] == BluetoothProfile.STATE_CONNECTED) {
143                 return mConnectedDevices;
144             }
145         }
146         return new ArrayList<BluetoothDevice>();
147     }
148 
getConnectionState(BluetoothDevice device)149     int getConnectionState(BluetoothDevice device) {
150         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
151         return (mConnectedDevices.contains(device) ? BluetoothProfile.STATE_CONNECTED
152                                                 : BluetoothProfile.STATE_DISCONNECTED);
153     }
154 
sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState)155     public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
156         if (DBG) Log.d(TAG, "sendPassThroughCmd");
157         Log.v(TAG, "keyCode: " + keyCode + " keyState: " + keyState);
158         if (device == null) {
159             throw new NullPointerException("device == null");
160         }
161         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
162         Message msg = mHandler.obtainMessage(MESSAGE_SEND_PASS_THROUGH_CMD,
163                 keyCode, keyState, device);
164         mHandler.sendMessage(msg);
165     }
166 
167     //Binder object: Must be static class or memory leak may occur
168     private static class BluetoothAvrcpControllerBinder extends IBluetoothAvrcpController.Stub
169         implements IProfileServiceBinder {
170         private AvrcpControllerService mService;
171 
getService()172         private AvrcpControllerService getService() {
173             if (!Utils.checkCaller()) {
174                 Log.w(TAG,"AVRCP call not allowed for non-active user");
175                 return null;
176             }
177 
178             if (mService != null && mService.isAvailable()) {
179                 return mService;
180             }
181             return null;
182         }
183 
BluetoothAvrcpControllerBinder(AvrcpControllerService svc)184         BluetoothAvrcpControllerBinder(AvrcpControllerService svc) {
185             mService = svc;
186         }
187 
cleanup()188         public boolean cleanup()  {
189             mService = null;
190             return true;
191         }
192 
getConnectedDevices()193         public List<BluetoothDevice> getConnectedDevices() {
194             AvrcpControllerService service = getService();
195             if (service == null) return new ArrayList<BluetoothDevice>(0);
196             return service.getConnectedDevices();
197         }
198 
getDevicesMatchingConnectionStates(int[] states)199         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
200             AvrcpControllerService service = getService();
201             if (service == null) return new ArrayList<BluetoothDevice>(0);
202             return service.getDevicesMatchingConnectionStates(states);
203         }
204 
getConnectionState(BluetoothDevice device)205         public int getConnectionState(BluetoothDevice device) {
206             AvrcpControllerService service = getService();
207             if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
208             return service.getConnectionState(device);
209         }
210 
sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState)211         public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
212             Log.v(TAG,"Binder Call: sendPassThroughCmd");
213             AvrcpControllerService service = getService();
214             if (service == null) return;
215             service.sendPassThroughCmd(device, keyCode, keyState);
216         }
217     };
218 
219     /** Handles Avrcp messages. */
220     private final class AvrcpMessageHandler extends Handler {
AvrcpMessageHandler(Looper looper)221         private AvrcpMessageHandler(Looper looper) {
222             super(looper);
223         }
224 
225         @Override
handleMessage(Message msg)226         public void handleMessage(Message msg) {
227             switch (msg.what) {
228             case MESSAGE_SEND_PASS_THROUGH_CMD:
229                 if (DBG) Log.v(TAG, "MESSAGE_SEND_PASS_THROUGH_CMD");
230                 BluetoothDevice device = (BluetoothDevice)msg.obj;
231                 sendPassThroughCommandNative(getByteAddress(device), msg.arg1, msg.arg2);
232                 break;
233             }
234         }
235     }
236 
onConnectionStateChanged(boolean connected, byte[] address)237     private void onConnectionStateChanged(boolean connected, byte[] address) {
238         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
239             (Utils.getAddressStringFromByte(address));
240         Log.d(TAG, "onConnectionStateChanged " + connected + " " + device);
241         Intent intent = new Intent(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED);
242         int oldState = (mConnectedDevices.contains(device) ? BluetoothProfile.STATE_CONNECTED
243                                                         : BluetoothProfile.STATE_DISCONNECTED);
244         int newState = (connected ? BluetoothProfile.STATE_CONNECTED
245                                   : BluetoothProfile.STATE_DISCONNECTED);
246         intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, oldState);
247         intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
248         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
249 //        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
250         sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
251         if (connected && oldState == BluetoothProfile.STATE_DISCONNECTED) {
252             mConnectedDevices.add(device);
253         } else if (!connected && oldState == BluetoothProfile.STATE_CONNECTED) {
254             mConnectedDevices.remove(device);
255         }
256     }
257 
handlePassthroughRsp(int id, int keyState)258     private void handlePassthroughRsp(int id, int keyState) {
259         Log.d(TAG, "passthrough response received as: key: "
260                                 + id + " state: " + keyState);
261     }
262 
getByteAddress(BluetoothDevice device)263     private byte[] getByteAddress(BluetoothDevice device) {
264         return Utils.getBytesFromAddress(device.getAddress());
265     }
266 
267     @Override
dump(StringBuilder sb)268     public void dump(StringBuilder sb) {
269         super.dump(sb);
270     }
271 
classInitNative()272     private native static void classInitNative();
initNative()273     private native void initNative();
cleanupNative()274     private native void cleanupNative();
sendPassThroughCommandNative(byte[] address, int keyCode, int keyState)275     private native boolean sendPassThroughCommandNative(byte[] address, int keyCode, int keyState);
276 }
277