ProfileService.java revision fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5
1b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpackage com.android.bluetooth.btservice;
2b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
374ae04c73312403e89db0f8e9bd9601d403b4783fredcimport java.util.HashMap;
474ae04c73312403e89db0f8e9bd9601d403b4783fredc
574ae04c73312403e89db0f8e9bd9601d403b4783fredcimport com.android.bluetooth.Utils;
674ae04c73312403e89db0f8e9bd9601d403b4783fredc
7b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.app.Service;
8b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.bluetooth.BluetoothAdapter;
974ae04c73312403e89db0f8e9bd9601d403b4783fredcimport android.bluetooth.BluetoothDevice;
1074ae04c73312403e89db0f8e9bd9601d403b4783fredcimport android.bluetooth.BluetoothProfile;
1174ae04c73312403e89db0f8e9bd9601d403b4783fredcimport android.content.Context;
12b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.content.Intent;
13b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.content.pm.PackageManager;
14b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.os.IBinder;
15b5cc776c9353a203cdde97e62b25f05d9633d14cfredcimport android.util.Log;
16b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
17b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpublic abstract class ProfileService extends Service {
18fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5Matthew Xie    private static final boolean DBG = false;
1974ae04c73312403e89db0f8e9bd9601d403b4783fredc    //For Debugging only
2074ae04c73312403e89db0f8e9bd9601d403b4783fredc    private static HashMap<String, Integer> sReferenceCount = new HashMap<String,Integer>();
2174ae04c73312403e89db0f8e9bd9601d403b4783fredc
22b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    public static final String BLUETOOTH_ADMIN_PERM =
23b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            android.Manifest.permission.BLUETOOTH_ADMIN;
24b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    public static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
25b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
2674ae04c73312403e89db0f8e9bd9601d403b4783fredc    public static interface IProfileServiceBinder extends IBinder {
2774ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean cleanup();
2874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
2931ba132491053bc86d419a7d51fc04af3299c076fredc    //Profile services will not be automatically restarted.
3031ba132491053bc86d419a7d51fc04af3299c076fredc    //They must be explicitly restarted by AdapterService
3131ba132491053bc86d419a7d51fc04af3299c076fredc    private static final int PROFILE_SERVICE_MODE=Service.START_NOT_STICKY;
32b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected String mName;
3374ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected BluetoothAdapter mAdapter;
3474ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected IProfileServiceBinder mBinder;
3574ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean mStartError=false;
3674ae04c73312403e89db0f8e9bd9601d403b4783fredc    private boolean mCleaningUp = false;
37b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
38b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected String getName() {
39b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        return getClass().getSimpleName();
40b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
41b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
4274ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean isAvailable() {
4374ae04c73312403e89db0f8e9bd9601d403b4783fredc        return !mStartError && !mCleaningUp;
4474ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
4574ae04c73312403e89db0f8e9bd9601d403b4783fredc
4674ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected abstract IProfileServiceBinder initBinder();
47b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected abstract boolean start();
48b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected abstract boolean stop();
4974ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean cleanup() {
5074ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
5174ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
52b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
5374ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected ProfileService() {
54b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        mName = getName();
5574ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) {
5674ae04c73312403e89db0f8e9bd9601d403b4783fredc            synchronized (sReferenceCount) {
5774ae04c73312403e89db0f8e9bd9601d403b4783fredc                Integer refCount = sReferenceCount.get(mName);
5874ae04c73312403e89db0f8e9bd9601d403b4783fredc                if (refCount==null) {
5974ae04c73312403e89db0f8e9bd9601d403b4783fredc                    refCount = 1;
6074ae04c73312403e89db0f8e9bd9601d403b4783fredc                } else {
6174ae04c73312403e89db0f8e9bd9601d403b4783fredc                    refCount = refCount+1;
6274ae04c73312403e89db0f8e9bd9601d403b4783fredc                }
6374ae04c73312403e89db0f8e9bd9601d403b4783fredc                sReferenceCount.put(mName, refCount);
6474ae04c73312403e89db0f8e9bd9601d403b4783fredc                log("REFCOUNT: CREATED. INSTANCE_COUNT=" +refCount);
6574ae04c73312403e89db0f8e9bd9601d403b4783fredc            }
66b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
6731ba132491053bc86d419a7d51fc04af3299c076fredc    }
6831ba132491053bc86d419a7d51fc04af3299c076fredc
6974ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected void finalize() {
7074ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) {
7174ae04c73312403e89db0f8e9bd9601d403b4783fredc            synchronized (sReferenceCount) {
7274ae04c73312403e89db0f8e9bd9601d403b4783fredc                Integer refCount = sReferenceCount.get(mName);
7374ae04c73312403e89db0f8e9bd9601d403b4783fredc                if (refCount!=null) {
7474ae04c73312403e89db0f8e9bd9601d403b4783fredc                    refCount = refCount-1;
7574ae04c73312403e89db0f8e9bd9601d403b4783fredc                } else {
7674ae04c73312403e89db0f8e9bd9601d403b4783fredc                    refCount = 0;
7774ae04c73312403e89db0f8e9bd9601d403b4783fredc                }
7874ae04c73312403e89db0f8e9bd9601d403b4783fredc                sReferenceCount.put(mName, refCount);
7974ae04c73312403e89db0f8e9bd9601d403b4783fredc                log("REFCOUNT: FINALIZED. INSTANCE_COUNT=" +refCount);
80b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            }
81b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
82b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
83b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
8474ae04c73312403e89db0f8e9bd9601d403b4783fredc    @Override
8574ae04c73312403e89db0f8e9bd9601d403b4783fredc    public void onCreate() {
8674ae04c73312403e89db0f8e9bd9601d403b4783fredc        log("onCreate");
8774ae04c73312403e89db0f8e9bd9601d403b4783fredc        super.onCreate();
8874ae04c73312403e89db0f8e9bd9601d403b4783fredc        mAdapter = BluetoothAdapter.getDefaultAdapter();
8974ae04c73312403e89db0f8e9bd9601d403b4783fredc        mBinder = initBinder();
9074ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
9174ae04c73312403e89db0f8e9bd9601d403b4783fredc
9231ba132491053bc86d419a7d51fc04af3299c076fredc    public int onStartCommand(Intent intent, int flags, int startId) {
9331ba132491053bc86d419a7d51fc04af3299c076fredc        log("onStartCommand()");
94b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        if (mStartError || mAdapter == null) {
95b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            Log.w(mName, "Stopping profile service: device does not have BT");
9631ba132491053bc86d419a7d51fc04af3299c076fredc            doStop(intent);
9731ba132491053bc86d419a7d51fc04af3299c076fredc            return PROFILE_SERVICE_MODE;
98b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
99b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
100b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) {
101b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            Log.e(mName, "Permission denied!");
10231ba132491053bc86d419a7d51fc04af3299c076fredc            return PROFILE_SERVICE_MODE;
103b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
104b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
10531ba132491053bc86d419a7d51fc04af3299c076fredc        if (intent == null) {
10631ba132491053bc86d419a7d51fc04af3299c076fredc            Log.d(mName, "Restarting profile service...");
10731ba132491053bc86d419a7d51fc04af3299c076fredc            return PROFILE_SERVICE_MODE;
10831ba132491053bc86d419a7d51fc04af3299c076fredc        } else {
10931ba132491053bc86d419a7d51fc04af3299c076fredc            String action = intent.getStringExtra(AdapterService.EXTRA_ACTION);
11031ba132491053bc86d419a7d51fc04af3299c076fredc            if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
11131ba132491053bc86d419a7d51fc04af3299c076fredc                int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
11231ba132491053bc86d419a7d51fc04af3299c076fredc                if(state==BluetoothAdapter.STATE_OFF) {
11331ba132491053bc86d419a7d51fc04af3299c076fredc                    Log.d(mName, "Received stop request...Stopping profile...");
11431ba132491053bc86d419a7d51fc04af3299c076fredc                    doStop(intent);
11531ba132491053bc86d419a7d51fc04af3299c076fredc                } else if (state == BluetoothAdapter.STATE_ON) {
11631ba132491053bc86d419a7d51fc04af3299c076fredc                    Log.d(mName, "Received start request. Starting profile...");
11731ba132491053bc86d419a7d51fc04af3299c076fredc                    doStart(intent);
11831ba132491053bc86d419a7d51fc04af3299c076fredc                }
119b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            }
120b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
12131ba132491053bc86d419a7d51fc04af3299c076fredc        return PROFILE_SERVICE_MODE;
122b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
123b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
12474ae04c73312403e89db0f8e9bd9601d403b4783fredc    public IBinder onBind(Intent intent) {
12574ae04c73312403e89db0f8e9bd9601d403b4783fredc        log("onBind");
12674ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mBinder;
12774ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
12874ae04c73312403e89db0f8e9bd9601d403b4783fredc
12974ae04c73312403e89db0f8e9bd9601d403b4783fredc    public boolean onUnbind(Intent intent) {
13074ae04c73312403e89db0f8e9bd9601d403b4783fredc        log("onUnbind");
13174ae04c73312403e89db0f8e9bd9601d403b4783fredc        return super.onUnbind(intent);
13274ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
13374ae04c73312403e89db0f8e9bd9601d403b4783fredc
134b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    @Override
135b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    public void onDestroy() {
136b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        log("Destroying service.");
13774ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (mCleaningUp) {
13874ae04c73312403e89db0f8e9bd9601d403b4783fredc            log("Cleanup already started... Skipping cleanup()...");
13974ae04c73312403e89db0f8e9bd9601d403b4783fredc        } else {
14074ae04c73312403e89db0f8e9bd9601d403b4783fredc            log("cleanup()");
14174ae04c73312403e89db0f8e9bd9601d403b4783fredc            mCleaningUp = true;
14274ae04c73312403e89db0f8e9bd9601d403b4783fredc            cleanup();
14374ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (mBinder != null) {
14474ae04c73312403e89db0f8e9bd9601d403b4783fredc                mBinder.cleanup();
14574ae04c73312403e89db0f8e9bd9601d403b4783fredc                mBinder= null;
14674ae04c73312403e89db0f8e9bd9601d403b4783fredc            }
14774ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
14874ae04c73312403e89db0f8e9bd9601d403b4783fredc        super.onDestroy();
14974ae04c73312403e89db0f8e9bd9601d403b4783fredc        mAdapter = null;
15074ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
15174ae04c73312403e89db0f8e9bd9601d403b4783fredc
15274ae04c73312403e89db0f8e9bd9601d403b4783fredc    private void doStart(Intent intent) {
15374ae04c73312403e89db0f8e9bd9601d403b4783fredc        //Start service
15474ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (mAdapter == null) {
15574ae04c73312403e89db0f8e9bd9601d403b4783fredc            Log.e(mName, "Error starting profile. BluetoothAdapter is null");
15674ae04c73312403e89db0f8e9bd9601d403b4783fredc        } else {
15774ae04c73312403e89db0f8e9bd9601d403b4783fredc            log("start()");
15874ae04c73312403e89db0f8e9bd9601d403b4783fredc            mStartError = !start();
15974ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (!mStartError) {
16074ae04c73312403e89db0f8e9bd9601d403b4783fredc                notifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON);
16174ae04c73312403e89db0f8e9bd9601d403b4783fredc            } else {
16274ae04c73312403e89db0f8e9bd9601d403b4783fredc                Log.e(mName, "Error starting profile. BluetoothAdapter is null");
16374ae04c73312403e89db0f8e9bd9601d403b4783fredc            }
16474ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
165b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
166b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
16731ba132491053bc86d419a7d51fc04af3299c076fredc    private void doStop(Intent intent) {
168b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        if (stop()) {
16974ae04c73312403e89db0f8e9bd9601d403b4783fredc            log("stop()");
17074ae04c73312403e89db0f8e9bd9601d403b4783fredc            notifyProfileServiceStateChanged(BluetoothAdapter.STATE_OFF);
171b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            stopSelf();
172b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        } else {
173b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            Log.e(mName, "Unable to stop profile");
174b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
175b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
176b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
17774ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected void notifyProfileServiceStateChanged(int state) {
178b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        //Notify adapter service
179b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        AdapterService sAdapter = AdapterService.getAdapterService();
180b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        if (sAdapter!= null) {
18131ba132491053bc86d419a7d51fc04af3299c076fredc            sAdapter.onProfileServiceStateChanged(getClass().getName(), state);
182b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
183b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
184b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
18574ae04c73312403e89db0f8e9bd9601d403b4783fredc    public void notifyProfileConnectionStateChanged(BluetoothDevice device,
18674ae04c73312403e89db0f8e9bd9601d403b4783fredc            int profileId, int newState, int prevState) {
18774ae04c73312403e89db0f8e9bd9601d403b4783fredc        AdapterService svc = AdapterService.getAdapterService();
18874ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (svc != null) {
18974ae04c73312403e89db0f8e9bd9601d403b4783fredc            svc.onProfileConnectionStateChanged(device, profileId, newState, prevState);
19074ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
19174ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
19274ae04c73312403e89db0f8e9bd9601d403b4783fredc
19374ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected BluetoothDevice getDevice(byte[] address) {
19474ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
19574ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
196b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
197b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected void log(String msg) {
198b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        Log.d(mName, msg);
199b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
200b5cc776c9353a203cdde97e62b25f05d9633d14cfredc}
201