Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ba0baeb authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Extract dependencies for HeadsetStateMachine"

parents 31c98c95 096c1323
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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));
}

+28 −2
Original line number Diff line number Diff line
@@ -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";
@@ -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;
    }
+25 −35
Original line number Diff line number Diff line
@@ -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";

@@ -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
@@ -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]);
@@ -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) {
@@ -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) {
@@ -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();
@@ -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:
@@ -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];
@@ -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;
@@ -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
@@ -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);
        }
    }

@@ -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;
        }
+493 −0

File added.

Preview size limit exceeded, changes collapsed.

+67 −46
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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) {
@@ -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;
@@ -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) {
@@ -406,8 +443,6 @@ public class HeadsetService extends ProfileService {
        }
    }

    ;

    // API methods
    public static synchronized HeadsetService getHeadsetService() {
        if (sHeadsetService != null && sHeadsetService.isAvailable()) {
@@ -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