Loading android/app/jni/com_android_bluetooth_hfp.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -848,7 +848,7 @@ static JNINativeMethod sMethods[] = { int register_com_android_bluetooth_hfp(JNIEnv* env) { return jniRegisterNativeMethods( env, "com/android/bluetooth/hfp/HeadsetStateMachine", sMethods, env, "com/android/bluetooth/hfp/HeadsetNativeInterface", sMethods, NELEM(sMethods)); } Loading android/app/src/com/android/bluetooth/btservice/ProfileService.java +28 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ import com.android.bluetooth.Utils; import java.util.HashMap; /** * Base class for a background service that runs a Bluetooth profile */ public abstract class ProfileService extends Service { private static final boolean DBG = false; private static final String TAG = "BluetoothProfileService"; Loading Loading @@ -61,14 +64,37 @@ public abstract class ProfileService extends Service { return !mStartError && !mCleaningUp; } /** * Called in {@link #onCreate()} to init binder interface for this profile service * * @return initialized binder interface for this profile service */ protected abstract IProfileServiceBinder initBinder(); /** * Called in {@link #onCreate()} to init basic stuff in this service */ protected void create() {} /** * Called in {@link #onStartCommand(Intent, int, int)} when the service is started by intent * * @return True in successful condition, False otherwise */ protected abstract boolean start(); /** * Called in {@link #onStartCommand(Intent, int, int)} when the service is stopped by intent * * @return True in successful condition, False otherwise */ protected abstract boolean stop(); protected void create() {} /** * Called in {@link #onDestroy()} when this object is completely discarded * * @return True in successful condition, False otherwise */ protected boolean cleanup() { return true; } Loading android/app/src/com/android/bluetooth/hfp/AtPhonebook.java +25 −35 Original line number Diff line number Diff line Loading @@ -74,11 +74,9 @@ public class AtPhonebook { public int nameColumn; } ; private Context mContext; private ContentResolver mContentResolver; private HeadsetStateMachine mStateMachine; private HeadsetNativeInterface mNativeInterface; private String mCurrentPhonebook; private String mCharacterSet = "UTF-8"; Loading @@ -97,11 +95,11 @@ public class AtPhonebook { static final int TYPE_SET = 1; static final int TYPE_TEST = 2; public AtPhonebook(Context context, HeadsetStateMachine headsetState) { public AtPhonebook(Context context, HeadsetNativeInterface nativeInterface) { mContext = context; mPairingPackage = context.getString(R.string.pairing_ui_package); mContentResolver = context.getContentResolver(); mStateMachine = headsetState; mNativeInterface = nativeInterface; mPhonebooks.put("DC", new PhonebookResult()); // dialled calls mPhonebooks.put("RC", new PhonebookResult()); // received calls mPhonebooks.put("MC", new PhonebookResult()); // missed calls Loading Loading @@ -175,8 +173,7 @@ public class AtPhonebook { log("handleCscsCommand - Set Command"); String[] args = atString.split("="); if (args.length < 2 || !(args[1] instanceof String)) { mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(device)); mNativeInterface.atResponseCode(device, atCommandResult, atCommandErrorCode); break; } String characterSet = ((atString.split("="))[1]); Loading @@ -195,10 +192,9 @@ public class AtPhonebook { atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS; } if (atCommandResponse != null) { mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device)); mNativeInterface.atResponseString(device, atCommandResponse); } mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(device)); mNativeInterface.atResponseCode(device, atCommandResult, atCommandErrorCode); } public void handleCpbsCommand(String atString, int type, BluetoothDevice device) { Loading Loading @@ -265,10 +261,9 @@ public class AtPhonebook { atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS; } if (atCommandResponse != null) { mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device)); mNativeInterface.atResponseString(device, atCommandResponse); } mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(device)); mNativeInterface.atResponseCode(device, atCommandResult, atCommandErrorCode); } public void handleCpbrCommand(String atString, int type, BluetoothDevice remoteDevice) { Loading @@ -291,8 +286,8 @@ public class AtPhonebook { PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true); //false); if (pbr == null) { atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } size = pbr.cursor.getCount(); Loading @@ -306,12 +301,8 @@ public class AtPhonebook { } atCommandResponse = "+CPBR: (1-" + size + "),30,30"; atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK; if (atCommandResponse != null) { mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(remoteDevice)); } mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseString(remoteDevice, atCommandResponse); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; // Read PhoneBook Entries case TYPE_READ: Loading @@ -322,16 +313,16 @@ public class AtPhonebook { if (mCpbrIndex1 != -1) { /* handling a CPBR at the moment, reject this CPBR command */ atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } // Parse indexes int index1; int index2; if ((atString.split("=")).length < 2) { mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } String atCommand = (atString.split("="))[1]; Loading @@ -350,8 +341,8 @@ public class AtPhonebook { } catch (Exception e) { log("handleCpbrCommand - exception - invalid chars: " + e.toString()); atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } mCpbrIndex1 = index1; Loading @@ -363,14 +354,14 @@ public class AtPhonebook { mCheckingAccessPermission = false; atCommandResult = processCpbrCommand(remoteDevice); mCpbrIndex1 = mCpbrIndex2 = -1; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } else if (permission == BluetoothDevice.ACCESS_REJECTED) { mCheckingAccessPermission = false; mCpbrIndex1 = mCpbrIndex2 = -1; mStateMachine.atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR, BluetoothCmeError.AG_FAILURE, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, BluetoothCmeError.AG_FAILURE); } // If checkAccessPermission(remoteDevice) has returned // BluetoothDevice.ACCESS_UNKNOWN, we will continue the process in Loading @@ -381,8 +372,7 @@ public class AtPhonebook { default: log("handleCpbrCommand - invalid chars"); atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); } } Loading Loading @@ -608,12 +598,12 @@ public class AtPhonebook { record = "+CPBR: " + index + ",\"" + number + "\"," + regionType + ",\"" + name + "\""; record = record + "\r\n\r\n"; atCommandResponse = record; mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device)); mNativeInterface.atResponseString(device, atCommandResponse); if (!pbr.cursor.moveToNext()) { break; } } if (pbr != null && pbr.cursor != null) { if (pbr.cursor != null) { pbr.cursor.close(); pbr.cursor = null; } Loading android/app/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java 0 → 100644 +493 −0 File added.Preview size limit exceeded, changes collapsed. Show changes android/app/src/com/android/bluetooth/hfp/HeadsetService.java +67 −46 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.os.HandlerThread; import android.os.Message; import android.provider.Settings; import android.util.Log; Loading @@ -45,7 +46,10 @@ public class HeadsetService extends ProfileService { private static final String TAG = "HeadsetService"; private static final String MODIFY_PHONE_STATE = android.Manifest.permission.MODIFY_PHONE_STATE; private HandlerThread mStateMachinesThread; private HeadsetStateMachine mStateMachine; private boolean mStarted; private boolean mCreated; private static HeadsetService sHeadsetService; @Override Loading @@ -54,47 +58,75 @@ public class HeadsetService extends ProfileService { } @Override public IProfileServiceBinder initBinder() { public synchronized IProfileServiceBinder initBinder() { return new BluetoothHeadsetBinder(this); } @Override protected boolean start() { mStateMachine = HeadsetStateMachine.make(this); IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); protected synchronized void create() { mCreated = true; } @Override protected synchronized boolean start() { Log.i(TAG, "start()"); mStateMachinesThread = new HandlerThread("HeadsetService.StateMachines"); mStateMachinesThread.start(); mStateMachine = HeadsetStateMachine.make(this, mStateMachinesThread.getLooper(), HeadsetNativeInterface.getInstance()); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); try { registerReceiver(mHeadsetReceiver, filter); } catch (Exception e) { Log.w(TAG, "Unable to register headset receiver", e); } setHeadsetService(this); mStarted = true; return true; } @Override protected boolean stop() { try { unregisterReceiver(mHeadsetReceiver); } catch (Exception e) { Log.w(TAG, "Unable to unregister headset receiver", e); } if (mStateMachine != null) { mStateMachine.doQuit(); protected synchronized boolean stop() { Log.i(TAG, "stop()"); if (!mStarted) { Log.w(TAG, "stop() called before start()"); // Still return true because it is considered "stopped" return true; } mStarted = false; unregisterReceiver(mHeadsetReceiver); HeadsetStateMachine.destroy(mStateMachine); mStateMachine = null; mStateMachinesThread.quitSafely(); mStateMachinesThread = null; setHeadsetService(null); return true; } @Override protected boolean cleanup() { if (mStateMachine != null) { mStateMachine.cleanup(); protected synchronized boolean cleanup() { Log.i(TAG, "cleanup"); if (!mCreated) { Log.w(TAG, "cleanup() called before create()"); // Still return true as it is considered "not created" return true; } clearHeadsetService(); mCreated = false; return true; } /** * Checks if this service object is able to accept binder calls * @return True if the object can accept binder calls, False otherwise */ public synchronized boolean isAlive() { return isAvailable() && mCreated && mStarted; } // Handle messages from native (JNI) to Java void messageFromNative(HeadsetStackEvent stackEvent) { mStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT, stackEvent); } private final BroadcastReceiver mHeadsetReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading Loading @@ -123,7 +155,7 @@ public class HeadsetService extends ProfileService { */ private static class BluetoothHeadsetBinder extends IBluetoothHeadset.Stub implements IProfileServiceBinder { private HeadsetService mService; private volatile HeadsetService mService; BluetoothHeadsetBinder(HeadsetService svc) { mService = svc; Loading @@ -136,16 +168,21 @@ public class HeadsetService extends ProfileService { } private HeadsetService getService() { if (!Utils.checkCallerAllowManagedProfiles(mService)) { final HeadsetService service = mService; if (!Utils.checkCallerAllowManagedProfiles(service)) { Log.w(TAG, "Headset call not allowed for non-active user"); return null; } if (mService != null && mService.isAvailable()) { return mService; if (service == null) { Log.w(TAG, "Service is null"); return null; } if (!service.isAlive()) { Log.w(TAG, "Service is not alive"); return null; } return service; } @Override public boolean connect(BluetoothDevice device) { Loading Loading @@ -406,8 +443,6 @@ public class HeadsetService extends ProfileService { } } ; // API methods public static synchronized HeadsetService getHeadsetService() { if (sHeadsetService != null && sHeadsetService.isAvailable()) { Loading @@ -427,24 +462,10 @@ public class HeadsetService extends ProfileService { } private static synchronized void setHeadsetService(HeadsetService instance) { if (instance != null && instance.isAvailable()) { if (DBG) { Log.d(TAG, "setHeadsetService(): set to: " + sHeadsetService); Log.d(TAG, "setHeadsetService(): set to: " + instance); } sHeadsetService = instance; } else { if (DBG) { if (sHeadsetService == null) { Log.d(TAG, "setHeadsetService(): service not available"); } else if (!sHeadsetService.isAvailable()) { Log.d(TAG, "setHeadsetService(): service is cleaning up"); } } } } private static synchronized void clearHeadsetService() { sHeadsetService = null; } public boolean connect(BluetoothDevice device) { Loading Loading
android/app/jni/com_android_bluetooth_hfp.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -848,7 +848,7 @@ static JNINativeMethod sMethods[] = { int register_com_android_bluetooth_hfp(JNIEnv* env) { return jniRegisterNativeMethods( env, "com/android/bluetooth/hfp/HeadsetStateMachine", sMethods, env, "com/android/bluetooth/hfp/HeadsetNativeInterface", sMethods, NELEM(sMethods)); } Loading
android/app/src/com/android/bluetooth/btservice/ProfileService.java +28 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ import com.android.bluetooth.Utils; import java.util.HashMap; /** * Base class for a background service that runs a Bluetooth profile */ public abstract class ProfileService extends Service { private static final boolean DBG = false; private static final String TAG = "BluetoothProfileService"; Loading Loading @@ -61,14 +64,37 @@ public abstract class ProfileService extends Service { return !mStartError && !mCleaningUp; } /** * Called in {@link #onCreate()} to init binder interface for this profile service * * @return initialized binder interface for this profile service */ protected abstract IProfileServiceBinder initBinder(); /** * Called in {@link #onCreate()} to init basic stuff in this service */ protected void create() {} /** * Called in {@link #onStartCommand(Intent, int, int)} when the service is started by intent * * @return True in successful condition, False otherwise */ protected abstract boolean start(); /** * Called in {@link #onStartCommand(Intent, int, int)} when the service is stopped by intent * * @return True in successful condition, False otherwise */ protected abstract boolean stop(); protected void create() {} /** * Called in {@link #onDestroy()} when this object is completely discarded * * @return True in successful condition, False otherwise */ protected boolean cleanup() { return true; } Loading
android/app/src/com/android/bluetooth/hfp/AtPhonebook.java +25 −35 Original line number Diff line number Diff line Loading @@ -74,11 +74,9 @@ public class AtPhonebook { public int nameColumn; } ; private Context mContext; private ContentResolver mContentResolver; private HeadsetStateMachine mStateMachine; private HeadsetNativeInterface mNativeInterface; private String mCurrentPhonebook; private String mCharacterSet = "UTF-8"; Loading @@ -97,11 +95,11 @@ public class AtPhonebook { static final int TYPE_SET = 1; static final int TYPE_TEST = 2; public AtPhonebook(Context context, HeadsetStateMachine headsetState) { public AtPhonebook(Context context, HeadsetNativeInterface nativeInterface) { mContext = context; mPairingPackage = context.getString(R.string.pairing_ui_package); mContentResolver = context.getContentResolver(); mStateMachine = headsetState; mNativeInterface = nativeInterface; mPhonebooks.put("DC", new PhonebookResult()); // dialled calls mPhonebooks.put("RC", new PhonebookResult()); // received calls mPhonebooks.put("MC", new PhonebookResult()); // missed calls Loading Loading @@ -175,8 +173,7 @@ public class AtPhonebook { log("handleCscsCommand - Set Command"); String[] args = atString.split("="); if (args.length < 2 || !(args[1] instanceof String)) { mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(device)); mNativeInterface.atResponseCode(device, atCommandResult, atCommandErrorCode); break; } String characterSet = ((atString.split("="))[1]); Loading @@ -195,10 +192,9 @@ public class AtPhonebook { atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS; } if (atCommandResponse != null) { mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device)); mNativeInterface.atResponseString(device, atCommandResponse); } mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(device)); mNativeInterface.atResponseCode(device, atCommandResult, atCommandErrorCode); } public void handleCpbsCommand(String atString, int type, BluetoothDevice device) { Loading Loading @@ -265,10 +261,9 @@ public class AtPhonebook { atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS; } if (atCommandResponse != null) { mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device)); mNativeInterface.atResponseString(device, atCommandResponse); } mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(device)); mNativeInterface.atResponseCode(device, atCommandResult, atCommandErrorCode); } public void handleCpbrCommand(String atString, int type, BluetoothDevice remoteDevice) { Loading @@ -291,8 +286,8 @@ public class AtPhonebook { PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true); //false); if (pbr == null) { atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } size = pbr.cursor.getCount(); Loading @@ -306,12 +301,8 @@ public class AtPhonebook { } atCommandResponse = "+CPBR: (1-" + size + "),30,30"; atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK; if (atCommandResponse != null) { mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(remoteDevice)); } mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseString(remoteDevice, atCommandResponse); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; // Read PhoneBook Entries case TYPE_READ: Loading @@ -322,16 +313,16 @@ public class AtPhonebook { if (mCpbrIndex1 != -1) { /* handling a CPBR at the moment, reject this CPBR command */ atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } // Parse indexes int index1; int index2; if ((atString.split("=")).length < 2) { mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } String atCommand = (atString.split("="))[1]; Loading @@ -350,8 +341,8 @@ public class AtPhonebook { } catch (Exception e) { log("handleCpbrCommand - exception - invalid chars: " + e.toString()); atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } mCpbrIndex1 = index1; Loading @@ -363,14 +354,14 @@ public class AtPhonebook { mCheckingAccessPermission = false; atCommandResult = processCpbrCommand(remoteDevice); mCpbrIndex1 = mCpbrIndex2 = -1; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); break; } else if (permission == BluetoothDevice.ACCESS_REJECTED) { mCheckingAccessPermission = false; mCpbrIndex1 = mCpbrIndex2 = -1; mStateMachine.atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR, BluetoothCmeError.AG_FAILURE, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, BluetoothCmeError.AG_FAILURE); } // If checkAccessPermission(remoteDevice) has returned // BluetoothDevice.ACCESS_UNKNOWN, we will continue the process in Loading @@ -381,8 +372,7 @@ public class AtPhonebook { default: log("handleCpbrCommand - invalid chars"); atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS; mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(remoteDevice)); mNativeInterface.atResponseCode(remoteDevice, atCommandResult, atCommandErrorCode); } } Loading Loading @@ -608,12 +598,12 @@ public class AtPhonebook { record = "+CPBR: " + index + ",\"" + number + "\"," + regionType + ",\"" + name + "\""; record = record + "\r\n\r\n"; atCommandResponse = record; mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device)); mNativeInterface.atResponseString(device, atCommandResponse); if (!pbr.cursor.moveToNext()) { break; } } if (pbr != null && pbr.cursor != null) { if (pbr.cursor != null) { pbr.cursor.close(); pbr.cursor = null; } Loading
android/app/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java 0 → 100644 +493 −0 File added.Preview size limit exceeded, changes collapsed. Show changes
android/app/src/com/android/bluetooth/hfp/HeadsetService.java +67 −46 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.os.HandlerThread; import android.os.Message; import android.provider.Settings; import android.util.Log; Loading @@ -45,7 +46,10 @@ public class HeadsetService extends ProfileService { private static final String TAG = "HeadsetService"; private static final String MODIFY_PHONE_STATE = android.Manifest.permission.MODIFY_PHONE_STATE; private HandlerThread mStateMachinesThread; private HeadsetStateMachine mStateMachine; private boolean mStarted; private boolean mCreated; private static HeadsetService sHeadsetService; @Override Loading @@ -54,47 +58,75 @@ public class HeadsetService extends ProfileService { } @Override public IProfileServiceBinder initBinder() { public synchronized IProfileServiceBinder initBinder() { return new BluetoothHeadsetBinder(this); } @Override protected boolean start() { mStateMachine = HeadsetStateMachine.make(this); IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); protected synchronized void create() { mCreated = true; } @Override protected synchronized boolean start() { Log.i(TAG, "start()"); mStateMachinesThread = new HandlerThread("HeadsetService.StateMachines"); mStateMachinesThread.start(); mStateMachine = HeadsetStateMachine.make(this, mStateMachinesThread.getLooper(), HeadsetNativeInterface.getInstance()); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); try { registerReceiver(mHeadsetReceiver, filter); } catch (Exception e) { Log.w(TAG, "Unable to register headset receiver", e); } setHeadsetService(this); mStarted = true; return true; } @Override protected boolean stop() { try { unregisterReceiver(mHeadsetReceiver); } catch (Exception e) { Log.w(TAG, "Unable to unregister headset receiver", e); } if (mStateMachine != null) { mStateMachine.doQuit(); protected synchronized boolean stop() { Log.i(TAG, "stop()"); if (!mStarted) { Log.w(TAG, "stop() called before start()"); // Still return true because it is considered "stopped" return true; } mStarted = false; unregisterReceiver(mHeadsetReceiver); HeadsetStateMachine.destroy(mStateMachine); mStateMachine = null; mStateMachinesThread.quitSafely(); mStateMachinesThread = null; setHeadsetService(null); return true; } @Override protected boolean cleanup() { if (mStateMachine != null) { mStateMachine.cleanup(); protected synchronized boolean cleanup() { Log.i(TAG, "cleanup"); if (!mCreated) { Log.w(TAG, "cleanup() called before create()"); // Still return true as it is considered "not created" return true; } clearHeadsetService(); mCreated = false; return true; } /** * Checks if this service object is able to accept binder calls * @return True if the object can accept binder calls, False otherwise */ public synchronized boolean isAlive() { return isAvailable() && mCreated && mStarted; } // Handle messages from native (JNI) to Java void messageFromNative(HeadsetStackEvent stackEvent) { mStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT, stackEvent); } private final BroadcastReceiver mHeadsetReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading Loading @@ -123,7 +155,7 @@ public class HeadsetService extends ProfileService { */ private static class BluetoothHeadsetBinder extends IBluetoothHeadset.Stub implements IProfileServiceBinder { private HeadsetService mService; private volatile HeadsetService mService; BluetoothHeadsetBinder(HeadsetService svc) { mService = svc; Loading @@ -136,16 +168,21 @@ public class HeadsetService extends ProfileService { } private HeadsetService getService() { if (!Utils.checkCallerAllowManagedProfiles(mService)) { final HeadsetService service = mService; if (!Utils.checkCallerAllowManagedProfiles(service)) { Log.w(TAG, "Headset call not allowed for non-active user"); return null; } if (mService != null && mService.isAvailable()) { return mService; if (service == null) { Log.w(TAG, "Service is null"); return null; } if (!service.isAlive()) { Log.w(TAG, "Service is not alive"); return null; } return service; } @Override public boolean connect(BluetoothDevice device) { Loading Loading @@ -406,8 +443,6 @@ public class HeadsetService extends ProfileService { } } ; // API methods public static synchronized HeadsetService getHeadsetService() { if (sHeadsetService != null && sHeadsetService.isAvailable()) { Loading @@ -427,24 +462,10 @@ public class HeadsetService extends ProfileService { } private static synchronized void setHeadsetService(HeadsetService instance) { if (instance != null && instance.isAvailable()) { if (DBG) { Log.d(TAG, "setHeadsetService(): set to: " + sHeadsetService); Log.d(TAG, "setHeadsetService(): set to: " + instance); } sHeadsetService = instance; } else { if (DBG) { if (sHeadsetService == null) { Log.d(TAG, "setHeadsetService(): service not available"); } else if (!sHeadsetService.isAvailable()) { Log.d(TAG, "setHeadsetService(): service is cleaning up"); } } } } private static synchronized void clearHeadsetService() { sHeadsetService = null; } public boolean connect(BluetoothDevice device) { Loading