1ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu/* 2ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Copyright (C) 2012 The Android Open Source Project 3ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 4ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Licensed under the Apache License, Version 2.0 (the "License"); 5ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * you may not use this file except in compliance with the License. 6ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * You may obtain a copy of the License at 7ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 8ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * http://www.apache.org/licenses/LICENSE-2.0 9ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 10ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Unless required by applicable law or agreed to in writing, software 11ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * distributed under the License is distributed on an "AS IS" BASIS, 12ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * See the License for the specific language governing permissions and 14ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * limitations under the License. 15ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu */ 16ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu 17b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpackage com.android.bluetooth.btservice; 18b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 1974ae04c73312403e89db0f8e9bd9601d403b4783fredcimport java.util.HashMap; 2074ae04c73312403e89db0f8e9bd9601d403b4783fredc 2174ae04c73312403e89db0f8e9bd9601d403b4783fredcimport com.android.bluetooth.Utils; 2274ae04c73312403e89db0f8e9bd9601d403b4783fredc 23b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.app.Service; 24b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.bluetooth.BluetoothAdapter; 2574ae04c73312403e89db0f8e9bd9601d403b4783fredcimport android.bluetooth.BluetoothDevice; 2674ae04c73312403e89db0f8e9bd9601d403b4783fredcimport android.bluetooth.BluetoothProfile; 2774ae04c73312403e89db0f8e9bd9601d403b4783fredcimport android.content.Context; 28b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.content.Intent; 29b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.content.pm.PackageManager; 30b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.os.IBinder; 31b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.util.Log; 32b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 33b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpublic abstract class ProfileService extends Service { 34fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5Matthew Xie private static final boolean DBG = false; 3574ae04c73312403e89db0f8e9bd9601d403b4783fredc //For Debugging only 3674ae04c73312403e89db0f8e9bd9601d403b4783fredc private static HashMap<String, Integer> sReferenceCount = new HashMap<String,Integer>(); 3774ae04c73312403e89db0f8e9bd9601d403b4783fredc 38b5cc776c9353a203cdde97e62b25f05d9633d14cfredc public static final String BLUETOOTH_ADMIN_PERM = 39b5cc776c9353a203cdde97e62b25f05d9633d14cfredc android.Manifest.permission.BLUETOOTH_ADMIN; 40b5cc776c9353a203cdde97e62b25f05d9633d14cfredc public static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 41b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 4274ae04c73312403e89db0f8e9bd9601d403b4783fredc public static interface IProfileServiceBinder extends IBinder { 4374ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean cleanup(); 4474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 4531ba132491053bc86d419a7d51fc04af3299c076fredc //Profile services will not be automatically restarted. 4631ba132491053bc86d419a7d51fc04af3299c076fredc //They must be explicitly restarted by AdapterService 4731ba132491053bc86d419a7d51fc04af3299c076fredc private static final int PROFILE_SERVICE_MODE=Service.START_NOT_STICKY; 48b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected String mName; 4974ae04c73312403e89db0f8e9bd9601d403b4783fredc protected BluetoothAdapter mAdapter; 5074ae04c73312403e89db0f8e9bd9601d403b4783fredc protected IProfileServiceBinder mBinder; 5174ae04c73312403e89db0f8e9bd9601d403b4783fredc protected boolean mStartError=false; 5274ae04c73312403e89db0f8e9bd9601d403b4783fredc private boolean mCleaningUp = false; 53b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 54b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected String getName() { 55b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return getClass().getSimpleName(); 56b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 57b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 5874ae04c73312403e89db0f8e9bd9601d403b4783fredc protected boolean isAvailable() { 5974ae04c73312403e89db0f8e9bd9601d403b4783fredc return !mStartError && !mCleaningUp; 6074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 6174ae04c73312403e89db0f8e9bd9601d403b4783fredc 6274ae04c73312403e89db0f8e9bd9601d403b4783fredc protected abstract IProfileServiceBinder initBinder(); 63b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected abstract boolean start(); 64b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected abstract boolean stop(); 6574ae04c73312403e89db0f8e9bd9601d403b4783fredc protected boolean cleanup() { 6674ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 6774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 68b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 6974ae04c73312403e89db0f8e9bd9601d403b4783fredc protected ProfileService() { 70b5cc776c9353a203cdde97e62b25f05d9633d14cfredc mName = getName(); 7174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) { 7274ae04c73312403e89db0f8e9bd9601d403b4783fredc synchronized (sReferenceCount) { 7374ae04c73312403e89db0f8e9bd9601d403b4783fredc Integer refCount = sReferenceCount.get(mName); 7474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (refCount==null) { 7574ae04c73312403e89db0f8e9bd9601d403b4783fredc refCount = 1; 7674ae04c73312403e89db0f8e9bd9601d403b4783fredc } else { 7774ae04c73312403e89db0f8e9bd9601d403b4783fredc refCount = refCount+1; 7874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 7974ae04c73312403e89db0f8e9bd9601d403b4783fredc sReferenceCount.put(mName, refCount); 800f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("REFCOUNT: CREATED. INSTANCE_COUNT=" +refCount); 8174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 82b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 8331ba132491053bc86d419a7d51fc04af3299c076fredc } 8431ba132491053bc86d419a7d51fc04af3299c076fredc 8574ae04c73312403e89db0f8e9bd9601d403b4783fredc protected void finalize() { 8674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) { 8774ae04c73312403e89db0f8e9bd9601d403b4783fredc synchronized (sReferenceCount) { 8874ae04c73312403e89db0f8e9bd9601d403b4783fredc Integer refCount = sReferenceCount.get(mName); 8974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (refCount!=null) { 9074ae04c73312403e89db0f8e9bd9601d403b4783fredc refCount = refCount-1; 9174ae04c73312403e89db0f8e9bd9601d403b4783fredc } else { 9274ae04c73312403e89db0f8e9bd9601d403b4783fredc refCount = 0; 9374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 9474ae04c73312403e89db0f8e9bd9601d403b4783fredc sReferenceCount.put(mName, refCount); 9574ae04c73312403e89db0f8e9bd9601d403b4783fredc log("REFCOUNT: FINALIZED. INSTANCE_COUNT=" +refCount); 96b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 97b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 98b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 99b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 10074ae04c73312403e89db0f8e9bd9601d403b4783fredc @Override 10174ae04c73312403e89db0f8e9bd9601d403b4783fredc public void onCreate() { 1020f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("onCreate"); 10374ae04c73312403e89db0f8e9bd9601d403b4783fredc super.onCreate(); 10474ae04c73312403e89db0f8e9bd9601d403b4783fredc mAdapter = BluetoothAdapter.getDefaultAdapter(); 10574ae04c73312403e89db0f8e9bd9601d403b4783fredc mBinder = initBinder(); 10674ae04c73312403e89db0f8e9bd9601d403b4783fredc } 10774ae04c73312403e89db0f8e9bd9601d403b4783fredc 10831ba132491053bc86d419a7d51fc04af3299c076fredc public int onStartCommand(Intent intent, int flags, int startId) { 1090f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("onStartCommand()"); 110b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if (mStartError || mAdapter == null) { 111b5cc776c9353a203cdde97e62b25f05d9633d14cfredc Log.w(mName, "Stopping profile service: device does not have BT"); 11231ba132491053bc86d419a7d51fc04af3299c076fredc doStop(intent); 11331ba132491053bc86d419a7d51fc04af3299c076fredc return PROFILE_SERVICE_MODE; 114b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 115b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 116b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) { 117b5cc776c9353a203cdde97e62b25f05d9633d14cfredc Log.e(mName, "Permission denied!"); 11831ba132491053bc86d419a7d51fc04af3299c076fredc return PROFILE_SERVICE_MODE; 119b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 120b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 12131ba132491053bc86d419a7d51fc04af3299c076fredc if (intent == null) { 12231ba132491053bc86d419a7d51fc04af3299c076fredc Log.d(mName, "Restarting profile service..."); 12331ba132491053bc86d419a7d51fc04af3299c076fredc return PROFILE_SERVICE_MODE; 12431ba132491053bc86d419a7d51fc04af3299c076fredc } else { 12531ba132491053bc86d419a7d51fc04af3299c076fredc String action = intent.getStringExtra(AdapterService.EXTRA_ACTION); 12631ba132491053bc86d419a7d51fc04af3299c076fredc if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) { 12731ba132491053bc86d419a7d51fc04af3299c076fredc int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 12831ba132491053bc86d419a7d51fc04af3299c076fredc if(state==BluetoothAdapter.STATE_OFF) { 12931ba132491053bc86d419a7d51fc04af3299c076fredc Log.d(mName, "Received stop request...Stopping profile..."); 13031ba132491053bc86d419a7d51fc04af3299c076fredc doStop(intent); 13131ba132491053bc86d419a7d51fc04af3299c076fredc } else if (state == BluetoothAdapter.STATE_ON) { 13231ba132491053bc86d419a7d51fc04af3299c076fredc Log.d(mName, "Received start request. Starting profile..."); 13331ba132491053bc86d419a7d51fc04af3299c076fredc doStart(intent); 13431ba132491053bc86d419a7d51fc04af3299c076fredc } 135b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 136b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 13731ba132491053bc86d419a7d51fc04af3299c076fredc return PROFILE_SERVICE_MODE; 138b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 139b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 14074ae04c73312403e89db0f8e9bd9601d403b4783fredc public IBinder onBind(Intent intent) { 1410f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("onBind"); 14274ae04c73312403e89db0f8e9bd9601d403b4783fredc return mBinder; 14374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 14474ae04c73312403e89db0f8e9bd9601d403b4783fredc 14574ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean onUnbind(Intent intent) { 1460f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("onUnbind"); 14774ae04c73312403e89db0f8e9bd9601d403b4783fredc return super.onUnbind(intent); 14874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 14974ae04c73312403e89db0f8e9bd9601d403b4783fredc 150b5cc776c9353a203cdde97e62b25f05d9633d14cfredc @Override 151b5cc776c9353a203cdde97e62b25f05d9633d14cfredc public void onDestroy() { 1520f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("Destroying service."); 15374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mCleaningUp) { 1540f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("Cleanup already started... Skipping cleanup()..."); 15574ae04c73312403e89db0f8e9bd9601d403b4783fredc } else { 1560f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("cleanup()"); 15774ae04c73312403e89db0f8e9bd9601d403b4783fredc mCleaningUp = true; 15874ae04c73312403e89db0f8e9bd9601d403b4783fredc cleanup(); 15974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mBinder != null) { 16074ae04c73312403e89db0f8e9bd9601d403b4783fredc mBinder.cleanup(); 16174ae04c73312403e89db0f8e9bd9601d403b4783fredc mBinder= null; 16274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 16374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 16474ae04c73312403e89db0f8e9bd9601d403b4783fredc super.onDestroy(); 16574ae04c73312403e89db0f8e9bd9601d403b4783fredc mAdapter = null; 16674ae04c73312403e89db0f8e9bd9601d403b4783fredc } 16774ae04c73312403e89db0f8e9bd9601d403b4783fredc 16874ae04c73312403e89db0f8e9bd9601d403b4783fredc private void doStart(Intent intent) { 16974ae04c73312403e89db0f8e9bd9601d403b4783fredc //Start service 17074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mAdapter == null) { 17174ae04c73312403e89db0f8e9bd9601d403b4783fredc Log.e(mName, "Error starting profile. BluetoothAdapter is null"); 17274ae04c73312403e89db0f8e9bd9601d403b4783fredc } else { 1730f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("start()"); 17474ae04c73312403e89db0f8e9bd9601d403b4783fredc mStartError = !start(); 17574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (!mStartError) { 17674ae04c73312403e89db0f8e9bd9601d403b4783fredc notifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON); 17774ae04c73312403e89db0f8e9bd9601d403b4783fredc } else { 17874ae04c73312403e89db0f8e9bd9601d403b4783fredc Log.e(mName, "Error starting profile. BluetoothAdapter is null"); 17974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 18074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 181b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 182b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 18331ba132491053bc86d419a7d51fc04af3299c076fredc private void doStop(Intent intent) { 184b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if (stop()) { 1850f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie if (DBG) log("stop()"); 18674ae04c73312403e89db0f8e9bd9601d403b4783fredc notifyProfileServiceStateChanged(BluetoothAdapter.STATE_OFF); 187b5cc776c9353a203cdde97e62b25f05d9633d14cfredc stopSelf(); 188b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } else { 189b5cc776c9353a203cdde97e62b25f05d9633d14cfredc Log.e(mName, "Unable to stop profile"); 190b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 191b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 192b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 19374ae04c73312403e89db0f8e9bd9601d403b4783fredc protected void notifyProfileServiceStateChanged(int state) { 194b5cc776c9353a203cdde97e62b25f05d9633d14cfredc //Notify adapter service 195b5cc776c9353a203cdde97e62b25f05d9633d14cfredc AdapterService sAdapter = AdapterService.getAdapterService(); 196b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if (sAdapter!= null) { 19731ba132491053bc86d419a7d51fc04af3299c076fredc sAdapter.onProfileServiceStateChanged(getClass().getName(), state); 198b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 199b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 200b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 20174ae04c73312403e89db0f8e9bd9601d403b4783fredc public void notifyProfileConnectionStateChanged(BluetoothDevice device, 20274ae04c73312403e89db0f8e9bd9601d403b4783fredc int profileId, int newState, int prevState) { 20374ae04c73312403e89db0f8e9bd9601d403b4783fredc AdapterService svc = AdapterService.getAdapterService(); 20474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (svc != null) { 20574ae04c73312403e89db0f8e9bd9601d403b4783fredc svc.onProfileConnectionStateChanged(device, profileId, newState, prevState); 20674ae04c73312403e89db0f8e9bd9601d403b4783fredc } 20774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 20874ae04c73312403e89db0f8e9bd9601d403b4783fredc 20974ae04c73312403e89db0f8e9bd9601d403b4783fredc protected BluetoothDevice getDevice(byte[] address) { 21074ae04c73312403e89db0f8e9bd9601d403b4783fredc return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 21174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 212b5cc776c9353a203cdde97e62b25f05d9633d14cfredc 213b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected void log(String msg) { 214b5cc776c9353a203cdde97e62b25f05d9633d14cfredc Log.d(mName, msg); 215b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 216b5cc776c9353a203cdde97e62b25f05d9633d14cfredc} 217