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

Commit 71f94b4c authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 4462748 from e8c95a78 to pi-release

Change-Id: Ib44757e4d73d9a1dddb66dc249f9d23ca88b9a73
parents c6601ba0 e8c95a78
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