1/* 2 * Copyright (C) 2012 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 17package com.android.bluetooth.btservice; 18 19import java.util.HashMap; 20 21import com.android.bluetooth.Utils; 22 23import android.app.Service; 24import android.bluetooth.BluetoothAdapter; 25import android.bluetooth.BluetoothDevice; 26import android.bluetooth.BluetoothProfile; 27import android.content.Context; 28import android.content.Intent; 29import android.content.pm.PackageManager; 30import android.os.IBinder; 31import android.util.Log; 32 33public abstract class ProfileService extends Service { 34 private static final boolean DBG = false; 35 //For Debugging only 36 private static HashMap<String, Integer> sReferenceCount = new HashMap<String,Integer>(); 37 38 public static final String BLUETOOTH_ADMIN_PERM = 39 android.Manifest.permission.BLUETOOTH_ADMIN; 40 public static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 41 42 public static interface IProfileServiceBinder extends IBinder { 43 public boolean cleanup(); 44 } 45 //Profile services will not be automatically restarted. 46 //They must be explicitly restarted by AdapterService 47 private static final int PROFILE_SERVICE_MODE=Service.START_NOT_STICKY; 48 protected String mName; 49 protected BluetoothAdapter mAdapter; 50 protected IProfileServiceBinder mBinder; 51 protected boolean mStartError=false; 52 private boolean mCleaningUp = false; 53 54 protected String getName() { 55 return getClass().getSimpleName(); 56 } 57 58 protected boolean isAvailable() { 59 return !mStartError && !mCleaningUp; 60 } 61 62 protected abstract IProfileServiceBinder initBinder(); 63 protected abstract boolean start(); 64 protected abstract boolean stop(); 65 protected boolean cleanup() { 66 return true; 67 } 68 69 protected ProfileService() { 70 mName = getName(); 71 if (DBG) { 72 synchronized (sReferenceCount) { 73 Integer refCount = sReferenceCount.get(mName); 74 if (refCount==null) { 75 refCount = 1; 76 } else { 77 refCount = refCount+1; 78 } 79 sReferenceCount.put(mName, refCount); 80 if (DBG) log("REFCOUNT: CREATED. INSTANCE_COUNT=" +refCount); 81 } 82 } 83 } 84 85 protected void finalize() { 86 if (DBG) { 87 synchronized (sReferenceCount) { 88 Integer refCount = sReferenceCount.get(mName); 89 if (refCount!=null) { 90 refCount = refCount-1; 91 } else { 92 refCount = 0; 93 } 94 sReferenceCount.put(mName, refCount); 95 log("REFCOUNT: FINALIZED. INSTANCE_COUNT=" +refCount); 96 } 97 } 98 } 99 100 @Override 101 public void onCreate() { 102 if (DBG) log("onCreate"); 103 super.onCreate(); 104 mAdapter = BluetoothAdapter.getDefaultAdapter(); 105 mBinder = initBinder(); 106 } 107 108 public int onStartCommand(Intent intent, int flags, int startId) { 109 if (DBG) log("onStartCommand()"); 110 if (mStartError || mAdapter == null) { 111 Log.w(mName, "Stopping profile service: device does not have BT"); 112 doStop(intent); 113 return PROFILE_SERVICE_MODE; 114 } 115 116 if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) { 117 Log.e(mName, "Permission denied!"); 118 return PROFILE_SERVICE_MODE; 119 } 120 121 if (intent == null) { 122 Log.d(mName, "Restarting profile service..."); 123 return PROFILE_SERVICE_MODE; 124 } else { 125 String action = intent.getStringExtra(AdapterService.EXTRA_ACTION); 126 if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) { 127 int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 128 if(state==BluetoothAdapter.STATE_OFF) { 129 Log.d(mName, "Received stop request...Stopping profile..."); 130 doStop(intent); 131 } else if (state == BluetoothAdapter.STATE_ON) { 132 Log.d(mName, "Received start request. Starting profile..."); 133 doStart(intent); 134 } 135 } 136 } 137 return PROFILE_SERVICE_MODE; 138 } 139 140 public IBinder onBind(Intent intent) { 141 if (DBG) log("onBind"); 142 return mBinder; 143 } 144 145 public boolean onUnbind(Intent intent) { 146 if (DBG) log("onUnbind"); 147 return super.onUnbind(intent); 148 } 149 150 @Override 151 public void onDestroy() { 152 if (DBG) log("Destroying service."); 153 if (mCleaningUp) { 154 if (DBG) log("Cleanup already started... Skipping cleanup()..."); 155 } else { 156 if (DBG) log("cleanup()"); 157 mCleaningUp = true; 158 cleanup(); 159 if (mBinder != null) { 160 mBinder.cleanup(); 161 mBinder= null; 162 } 163 } 164 super.onDestroy(); 165 mAdapter = null; 166 } 167 168 private void doStart(Intent intent) { 169 //Start service 170 if (mAdapter == null) { 171 Log.e(mName, "Error starting profile. BluetoothAdapter is null"); 172 } else { 173 if (DBG) log("start()"); 174 mStartError = !start(); 175 if (!mStartError) { 176 notifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON); 177 } else { 178 Log.e(mName, "Error starting profile. BluetoothAdapter is null"); 179 } 180 } 181 } 182 183 private void doStop(Intent intent) { 184 if (stop()) { 185 if (DBG) log("stop()"); 186 notifyProfileServiceStateChanged(BluetoothAdapter.STATE_OFF); 187 stopSelf(); 188 } else { 189 Log.e(mName, "Unable to stop profile"); 190 } 191 } 192 193 protected void notifyProfileServiceStateChanged(int state) { 194 //Notify adapter service 195 AdapterService sAdapter = AdapterService.getAdapterService(); 196 if (sAdapter!= null) { 197 sAdapter.onProfileServiceStateChanged(getClass().getName(), state); 198 } 199 } 200 201 public void notifyProfileConnectionStateChanged(BluetoothDevice device, 202 int profileId, int newState, int prevState) { 203 AdapterService svc = AdapterService.getAdapterService(); 204 if (svc != null) { 205 svc.onProfileConnectionStateChanged(device, profileId, newState, prevState); 206 } 207 } 208 209 protected BluetoothDevice getDevice(byte[] address) { 210 return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 211 } 212 213 protected void log(String msg) { 214 Log.d(mName, msg); 215 } 216} 217