ProfileService.java revision f7435f2f832ab1faa9ca254143796e9516905c63
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;
35abe1879f779481f9ee1a48b2de343097a6ddcf85Matthew Xie    private static final String TAG = "BluetoothProfileService";
36abe1879f779481f9ee1a48b2de343097a6ddcf85Matthew Xie
3774ae04c73312403e89db0f8e9bd9601d403b4783fredc    //For Debugging only
3874ae04c73312403e89db0f8e9bd9601d403b4783fredc    private static HashMap<String, Integer> sReferenceCount = new HashMap<String,Integer>();
3974ae04c73312403e89db0f8e9bd9601d403b4783fredc
40b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    public static final String BLUETOOTH_ADMIN_PERM =
41b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            android.Manifest.permission.BLUETOOTH_ADMIN;
42b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    public static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
43a08fff0ae81757bdab00ae8865a906c711d5572fWei Wang    public static final String BLUETOOTH_PRIVILEGED =
44a08fff0ae81757bdab00ae8865a906c711d5572fWei Wang        android.Manifest.permission.BLUETOOTH_PRIVILEGED;
45b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
4674ae04c73312403e89db0f8e9bd9601d403b4783fredc    public static interface IProfileServiceBinder extends IBinder {
4774ae04c73312403e89db0f8e9bd9601d403b4783fredc        public boolean cleanup();
4874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
4931ba132491053bc86d419a7d51fc04af3299c076fredc    //Profile services will not be automatically restarted.
5031ba132491053bc86d419a7d51fc04af3299c076fredc    //They must be explicitly restarted by AdapterService
5131ba132491053bc86d419a7d51fc04af3299c076fredc    private static final int PROFILE_SERVICE_MODE=Service.START_NOT_STICKY;
52b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected String mName;
5374ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected BluetoothAdapter mAdapter;
5474ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected IProfileServiceBinder mBinder;
5574ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean mStartError=false;
5674ae04c73312403e89db0f8e9bd9601d403b4783fredc    private boolean mCleaningUp = false;
57b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
58838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    private AdapterService mAdapterService;
59838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
60b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected String getName() {
61b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        return getClass().getSimpleName();
62b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
63b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
6474ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean isAvailable() {
6574ae04c73312403e89db0f8e9bd9601d403b4783fredc        return !mStartError && !mCleaningUp;
6674ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
6774ae04c73312403e89db0f8e9bd9601d403b4783fredc
6874ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected abstract IProfileServiceBinder initBinder();
69b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected abstract boolean start();
70b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected abstract boolean stop();
7174ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected boolean cleanup() {
7274ae04c73312403e89db0f8e9bd9601d403b4783fredc        return true;
7374ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
74b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
7574ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected ProfileService() {
76b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        mName = getName();
7774ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) {
7874ae04c73312403e89db0f8e9bd9601d403b4783fredc            synchronized (sReferenceCount) {
7974ae04c73312403e89db0f8e9bd9601d403b4783fredc                Integer refCount = sReferenceCount.get(mName);
8074ae04c73312403e89db0f8e9bd9601d403b4783fredc                if (refCount==null) {
8174ae04c73312403e89db0f8e9bd9601d403b4783fredc                    refCount = 1;
8274ae04c73312403e89db0f8e9bd9601d403b4783fredc                } else {
8374ae04c73312403e89db0f8e9bd9601d403b4783fredc                    refCount = refCount+1;
8474ae04c73312403e89db0f8e9bd9601d403b4783fredc                }
8574ae04c73312403e89db0f8e9bd9601d403b4783fredc                sReferenceCount.put(mName, refCount);
860f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie                if (DBG) log("REFCOUNT: CREATED. INSTANCE_COUNT=" +refCount);
8774ae04c73312403e89db0f8e9bd9601d403b4783fredc            }
88b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
8931ba132491053bc86d419a7d51fc04af3299c076fredc    }
9031ba132491053bc86d419a7d51fc04af3299c076fredc
9174ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected void finalize() {
9274ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (DBG) {
9374ae04c73312403e89db0f8e9bd9601d403b4783fredc            synchronized (sReferenceCount) {
9474ae04c73312403e89db0f8e9bd9601d403b4783fredc                Integer refCount = sReferenceCount.get(mName);
9574ae04c73312403e89db0f8e9bd9601d403b4783fredc                if (refCount!=null) {
9674ae04c73312403e89db0f8e9bd9601d403b4783fredc                    refCount = refCount-1;
9774ae04c73312403e89db0f8e9bd9601d403b4783fredc                } else {
9874ae04c73312403e89db0f8e9bd9601d403b4783fredc                    refCount = 0;
9974ae04c73312403e89db0f8e9bd9601d403b4783fredc                }
10074ae04c73312403e89db0f8e9bd9601d403b4783fredc                sReferenceCount.put(mName, refCount);
10174ae04c73312403e89db0f8e9bd9601d403b4783fredc                log("REFCOUNT: FINALIZED. INSTANCE_COUNT=" +refCount);
102b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            }
103b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
104b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
105b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
10674ae04c73312403e89db0f8e9bd9601d403b4783fredc    @Override
10774ae04c73312403e89db0f8e9bd9601d403b4783fredc    public void onCreate() {
1080f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie        if (DBG) log("onCreate");
10974ae04c73312403e89db0f8e9bd9601d403b4783fredc        super.onCreate();
11074ae04c73312403e89db0f8e9bd9601d403b4783fredc        mAdapter = BluetoothAdapter.getDefaultAdapter();
11174ae04c73312403e89db0f8e9bd9601d403b4783fredc        mBinder = initBinder();
112838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        mAdapterService = AdapterService.getAdapterService();
113abe1879f779481f9ee1a48b2de343097a6ddcf85Matthew Xie        if (mAdapterService != null) {
114abe1879f779481f9ee1a48b2de343097a6ddcf85Matthew Xie            mAdapterService.addProfile(this);
115abe1879f779481f9ee1a48b2de343097a6ddcf85Matthew Xie        } else {
116abe1879f779481f9ee1a48b2de343097a6ddcf85Matthew Xie            Log.w(TAG, "onCreate, null mAdapterService");
117abe1879f779481f9ee1a48b2de343097a6ddcf85Matthew Xie        }
11874ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
11974ae04c73312403e89db0f8e9bd9601d403b4783fredc
12031ba132491053bc86d419a7d51fc04af3299c076fredc    public int onStartCommand(Intent intent, int flags, int startId) {
1210f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie        if (DBG) log("onStartCommand()");
122b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        if (mStartError || mAdapter == null) {
123b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            Log.w(mName, "Stopping profile service: device does not have BT");
12431ba132491053bc86d419a7d51fc04af3299c076fredc            doStop(intent);
12531ba132491053bc86d419a7d51fc04af3299c076fredc            return PROFILE_SERVICE_MODE;
126b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
127b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
128b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) {
129b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            Log.e(mName, "Permission denied!");
13031ba132491053bc86d419a7d51fc04af3299c076fredc            return PROFILE_SERVICE_MODE;
131b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
132b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
13331ba132491053bc86d419a7d51fc04af3299c076fredc        if (intent == null) {
13431ba132491053bc86d419a7d51fc04af3299c076fredc            Log.d(mName, "Restarting profile service...");
13531ba132491053bc86d419a7d51fc04af3299c076fredc            return PROFILE_SERVICE_MODE;
13631ba132491053bc86d419a7d51fc04af3299c076fredc        } else {
13731ba132491053bc86d419a7d51fc04af3299c076fredc            String action = intent.getStringExtra(AdapterService.EXTRA_ACTION);
13831ba132491053bc86d419a7d51fc04af3299c076fredc            if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
13931ba132491053bc86d419a7d51fc04af3299c076fredc                int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
14031ba132491053bc86d419a7d51fc04af3299c076fredc                if(state==BluetoothAdapter.STATE_OFF) {
14131ba132491053bc86d419a7d51fc04af3299c076fredc                    Log.d(mName, "Received stop request...Stopping profile...");
14231ba132491053bc86d419a7d51fc04af3299c076fredc                    doStop(intent);
14331ba132491053bc86d419a7d51fc04af3299c076fredc                } else if (state == BluetoothAdapter.STATE_ON) {
14431ba132491053bc86d419a7d51fc04af3299c076fredc                    Log.d(mName, "Received start request. Starting profile...");
14531ba132491053bc86d419a7d51fc04af3299c076fredc                    doStart(intent);
14631ba132491053bc86d419a7d51fc04af3299c076fredc                }
147b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            }
148b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
14931ba132491053bc86d419a7d51fc04af3299c076fredc        return PROFILE_SERVICE_MODE;
150b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
151b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
15274ae04c73312403e89db0f8e9bd9601d403b4783fredc    public IBinder onBind(Intent intent) {
1530f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie        if (DBG) log("onBind");
15474ae04c73312403e89db0f8e9bd9601d403b4783fredc        return mBinder;
15574ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
15674ae04c73312403e89db0f8e9bd9601d403b4783fredc
15774ae04c73312403e89db0f8e9bd9601d403b4783fredc    public boolean onUnbind(Intent intent) {
1580f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie        if (DBG) log("onUnbind");
15974ae04c73312403e89db0f8e9bd9601d403b4783fredc        return super.onUnbind(intent);
16074ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
16174ae04c73312403e89db0f8e9bd9601d403b4783fredc
162838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    // for dumpsys support
163838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    public void dump(StringBuilder sb) {
164f5f90873574eefe5f50a7b383fcd8fefb961f66cAndre Eisenbach        sb.append("\nProfile: " + mName + "\n");
165838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
166838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
167f7435f2f832ab1faa9ca254143796e9516905c63Ajay Panicker    public void dumpProto(BluetoothProto.BluetoothLog proto) {
168f7435f2f832ab1faa9ca254143796e9516905c63Ajay Panicker        // Do nothing
169f7435f2f832ab1faa9ca254143796e9516905c63Ajay Panicker    }
170f7435f2f832ab1faa9ca254143796e9516905c63Ajay Panicker
171838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    // with indenting for subclasses
172838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    public static void println(StringBuilder sb, String s) {
173838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        sb.append("  ");
174838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        sb.append(s);
175838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        sb.append("\n");
176838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
177838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
178b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    @Override
179b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    public void onDestroy() {
1800f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie        if (DBG) log("Destroying service.");
181a1772b03b58d2821a621b40b7e8d1dba1213a556Andre Eisenbach        if (mAdapterService != null) mAdapterService.removeProfile(this);
182a1772b03b58d2821a621b40b7e8d1dba1213a556Andre Eisenbach
18374ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (mCleaningUp) {
1840f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie            if (DBG) log("Cleanup already started... Skipping cleanup()...");
18574ae04c73312403e89db0f8e9bd9601d403b4783fredc        } else {
1860f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie            if (DBG) log("cleanup()");
18774ae04c73312403e89db0f8e9bd9601d403b4783fredc            mCleaningUp = true;
18874ae04c73312403e89db0f8e9bd9601d403b4783fredc            cleanup();
18974ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (mBinder != null) {
19074ae04c73312403e89db0f8e9bd9601d403b4783fredc                mBinder.cleanup();
19174ae04c73312403e89db0f8e9bd9601d403b4783fredc                mBinder= null;
19274ae04c73312403e89db0f8e9bd9601d403b4783fredc            }
19374ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
19474ae04c73312403e89db0f8e9bd9601d403b4783fredc        super.onDestroy();
19574ae04c73312403e89db0f8e9bd9601d403b4783fredc        mAdapter = null;
19674ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
19774ae04c73312403e89db0f8e9bd9601d403b4783fredc
19874ae04c73312403e89db0f8e9bd9601d403b4783fredc    private void doStart(Intent intent) {
19974ae04c73312403e89db0f8e9bd9601d403b4783fredc        //Start service
20074ae04c73312403e89db0f8e9bd9601d403b4783fredc        if (mAdapter == null) {
20174ae04c73312403e89db0f8e9bd9601d403b4783fredc            Log.e(mName, "Error starting profile. BluetoothAdapter is null");
20274ae04c73312403e89db0f8e9bd9601d403b4783fredc        } else {
2030f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie            if (DBG) log("start()");
20474ae04c73312403e89db0f8e9bd9601d403b4783fredc            mStartError = !start();
20574ae04c73312403e89db0f8e9bd9601d403b4783fredc            if (!mStartError) {
20674ae04c73312403e89db0f8e9bd9601d403b4783fredc                notifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON);
20774ae04c73312403e89db0f8e9bd9601d403b4783fredc            } else {
20874ae04c73312403e89db0f8e9bd9601d403b4783fredc                Log.e(mName, "Error starting profile. BluetoothAdapter is null");
20974ae04c73312403e89db0f8e9bd9601d403b4783fredc            }
21074ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
211b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
212b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
21331ba132491053bc86d419a7d51fc04af3299c076fredc    private void doStop(Intent intent) {
214b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        if (stop()) {
2150f4ef70f0bc246b224f7b6da524128db89fcc8a7Matthew Xie            if (DBG) log("stop()");
21674ae04c73312403e89db0f8e9bd9601d403b4783fredc            notifyProfileServiceStateChanged(BluetoothAdapter.STATE_OFF);
217b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            stopSelf();
218b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        } else {
219b5cc776c9353a203cdde97e62b25f05d9633d14cfredc            Log.e(mName, "Unable to stop profile");
220b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
221b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
222b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
22374ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected void notifyProfileServiceStateChanged(int state) {
224b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        //Notify adapter service
225838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        if (mAdapterService != null) {
226838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood            mAdapterService.onProfileServiceStateChanged(getClass().getName(), state);
227b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        }
228b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
229b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
23074ae04c73312403e89db0f8e9bd9601d403b4783fredc    public void notifyProfileConnectionStateChanged(BluetoothDevice device,
23174ae04c73312403e89db0f8e9bd9601d403b4783fredc            int profileId, int newState, int prevState) {
232838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        if (mAdapterService != null) {
233838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood            mAdapterService.onProfileConnectionStateChanged(device, profileId, newState, prevState);
23474ae04c73312403e89db0f8e9bd9601d403b4783fredc        }
23574ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
23674ae04c73312403e89db0f8e9bd9601d403b4783fredc
23774ae04c73312403e89db0f8e9bd9601d403b4783fredc    protected BluetoothDevice getDevice(byte[] address) {
238f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        if(mAdapter != null){
239f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora            return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
240f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        }
241f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        return null;
24274ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
243b5cc776c9353a203cdde97e62b25f05d9633d14cfredc
244b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    protected void log(String msg) {
245b5cc776c9353a203cdde97e62b25f05d9633d14cfredc        Log.d(mName, msg);
246b5cc776c9353a203cdde97e62b25f05d9633d14cfredc    }
247b5cc776c9353a203cdde97e62b25f05d9633d14cfredc}
248