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

Commit 92d41d61 authored by William Escande's avatar William Escande Committed by Automerger Merge Worker
Browse files

Merge "SystemServer: Broadcast AutoOn state change" into main am: 4cd7ea67

parents 9a973860 4cd7ea67
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ package android.bluetooth {
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean unregisterBluetoothConnectionCallback(@NonNull android.bluetooth.BluetoothAdapter.BluetoothConnectionCallback);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int unregisterBluetoothQualityReportReadyCallback(@NonNull android.bluetooth.BluetoothAdapter.BluetoothQualityReportReadyCallback);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int unregisterPreferredAudioProfilesChangedCallback(@NonNull android.bluetooth.BluetoothAdapter.PreferredAudioProfilesChangedCallback);
    field @FlaggedApi("com.android.bluetooth.flags.auto_on_feature") @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_AUTO_ON_STATE_CHANGED = "android.bluetooth.action.AUTO_ON_STATE_CHANGED";
    field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
    field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE";
@@ -108,9 +109,12 @@ package android.bluetooth {
    field public static final int ACTIVE_DEVICE_PHONE_CALL = 1; // 0x1
    field public static final String AUDIO_MODE_DUPLEX = "audio_mode_duplex";
    field public static final String AUDIO_MODE_OUTPUT_ONLY = "audio_mode_output_only";
    field @FlaggedApi("com.android.bluetooth.flags.auto_on_feature") public static final int AUTO_ON_STATE_OFF = 1; // 0x1
    field @FlaggedApi("com.android.bluetooth.flags.auto_on_feature") public static final int AUTO_ON_STATE_ON = 2; // 0x2
    field public static final int BT_SNOOP_LOG_MODE_DISABLED = 0; // 0x0
    field public static final int BT_SNOOP_LOG_MODE_FILTERED = 1; // 0x1
    field public static final int BT_SNOOP_LOG_MODE_FULL = 2; // 0x2
    field @FlaggedApi("com.android.bluetooth.flags.auto_on_feature") public static final String EXTRA_AUTO_ON_STATE = "android.bluetooth.extra.AUTO_ON_STATE";
    field public static final String EXTRA_RFCOMM_LISTENER_ID = "android.bluetooth.adapter.extra.RFCOMM_LISTENER_ID";
    field public static final int STATE_BLE_ON = 15; // 0xf
  }
+47 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.bluetooth.BluetoothUtils.getSyncTimeout;

import static java.util.Objects.requireNonNull;

import android.annotation.BroadcastBehavior;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -802,6 +803,50 @@ public final class BluetoothAdapter {
            })
    public @interface ConnectionState {}

    /**
     * Broadcast Action: The AutoOn feature state has been changed for one user
     *
     * <p>Always contains the extra fields {@link #EXTRA_AUTO_ON_STATE}
     *
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_AUTO_ON_FEATURE)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    @BroadcastBehavior(registeredOnly = true, protectedBroadcast = true)
    public static final String ACTION_AUTO_ON_STATE_CHANGED =
            "android.bluetooth.action.AUTO_ON_STATE_CHANGED";

    /**
     * Used as an int extra field in {@link #ACTION_AUTO_ON_STATE_CHANGED} intents.
     *
     * <p>Possible values are: {@link #AUTO_ON_STATE_OFF}, {@link #AUTO_ON_STATE_ON}
     *
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_AUTO_ON_FEATURE)
    public static final String EXTRA_AUTO_ON_STATE = "android.bluetooth.extra.AUTO_ON_STATE";

    /**
     * Indicates the AutoOn feature is OFF.
     *
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_AUTO_ON_FEATURE)
    public static final int AUTO_ON_STATE_OFF = 1;

    /**
     * Indicates the AutoOn feature is ON.
     *
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_AUTO_ON_FEATURE)
    public static final int AUTO_ON_STATE_ON = 2;

    /**
     * Audio mode representing output only.
     *
@@ -5833,7 +5878,8 @@ public final class BluetoothAdapter {
    }

    /**
     * Set the value of the automatic restart of the Bluetooth stack for the current user
     * Set the value of the automatic restart of the Bluetooth stack for the current user. Client
     * can subscribe to update by listening to {@link ACTION_AUTO_ON_STATE_CHANGED} intent
     *
     * @param status true if the feature is enabled
     * @throws IllegalStateException if feature is not supported
+1 −0
Original line number Diff line number Diff line
@@ -178,6 +178,7 @@ android_robolectric_test {

    static_libs: [
        "androidx.test.core",
        "androidx.test.ext.truth",
        "kotlin-test",
        "kotlinx_coroutines",
        "kotlinx_coroutines_test",
+20 −6
Original line number Diff line number Diff line
@@ -18,6 +18,10 @@

package com.android.server.bluetooth

import android.bluetooth.BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED
import android.bluetooth.BluetoothAdapter.AUTO_ON_STATE_OFF
import android.bluetooth.BluetoothAdapter.AUTO_ON_STATE_ON
import android.bluetooth.BluetoothAdapter.EXTRA_AUTO_ON_STATE
import android.bluetooth.BluetoothAdapter.STATE_ON
import android.content.BroadcastReceiver
import android.content.ContentResolver
@@ -89,13 +93,13 @@ public fun pause() {
    timer = null
}

public fun notifyBluetoothOn(resolver: ContentResolver) {
public fun notifyBluetoothOn(context: Context) {
    timer?.cancel()
    timer = null

    if (!isFeatureSupportedForUser(resolver)) {
    if (!isFeatureSupportedForUser(context.contentResolver)) {
        val defaultFeatureValue = true
        if (!setFeatureEnabledForUserUnchecked(resolver, defaultFeatureValue)) {
        if (!setFeatureEnabledForUserUnchecked(context, defaultFeatureValue)) {
            Log.e(TAG, "Failed to set feature to its default value ${defaultFeatureValue}")
        } else {
            Log.i(TAG, "Feature was set to its default value ${defaultFeatureValue}")
@@ -122,7 +126,7 @@ public fun setUserEnabled(
    if (!isUserSupported(context.contentResolver)) {
        throw IllegalStateException("AutoOnFeature not supported for user: ${context.getUser()}")
    }
    if (!setFeatureEnabledForUserUnchecked(context.contentResolver, status)) {
    if (!setFeatureEnabledForUserUnchecked(context, status)) {
        throw IllegalStateException("AutoOnFeature database failure for user: ${context.getUser()}")
    }
    Counter.logIncrement(
@@ -272,8 +276,18 @@ private fun isFeatureSupportedForUser(resolver: ContentResolver): Boolean {
 *
 * @return whether the auto on feature is enabled for this user
 */
private fun setFeatureEnabledForUserUnchecked(resolver: ContentResolver, status: Boolean): Boolean {
    return Settings.Secure.putInt(resolver, USER_SETTINGS_KEY, if (status) 1 else 0)
private fun setFeatureEnabledForUserUnchecked(context: Context, status: Boolean): Boolean {
    val ret =
        Settings.Secure.putInt(context.contentResolver, USER_SETTINGS_KEY, if (status) 1 else 0)
    if (ret) {
        context.sendBroadcast(
            Intent(ACTION_AUTO_ON_STATE_CHANGED)
                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                .putExtra(EXTRA_AUTO_ON_STATE, if (status) AUTO_ON_STATE_ON else AUTO_ON_STATE_OFF),
            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
        )
    }
    return ret
}

// Listener is needed because code should be actionable prior to V API release
+32 −3
Original line number Diff line number Diff line
@@ -15,12 +15,14 @@
 */
package com.android.server.bluetooth.test

import android.app.Application
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
import android.os.Looper
import android.provider.Settings
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.truth.content.IntentSubject.assertThat
import com.android.server.bluetooth.BluetoothAdapterState
import com.android.server.bluetooth.HiddenApiListener
import com.android.server.bluetooth.Log
@@ -181,7 +183,7 @@ class AutoOnFeatureTest {

    @Test
    fun notifyBluetoothOn_whenNoTimer_noCrash() {
        notifyBluetoothOn(resolver)
        notifyBluetoothOn(context)

        assertThat(timer).isNull()
    }
@@ -189,7 +191,7 @@ class AutoOnFeatureTest {
    @Test
    fun notifyBluetoothOn_whenTimer_isNotScheduled() {
        setupTimer()
        notifyBluetoothOn(resolver)
        notifyBluetoothOn(context)

        shadowOf(looper).runToEndOfTasks()
        expect.that(callback_count).isEqualTo(0)
@@ -200,7 +202,7 @@ class AutoOnFeatureTest {
    fun notifyBluetoothOn_whenItWasNeverUsed_enableSettings() {
        restoreSettings()

        notifyBluetoothOn(resolver)
        notifyBluetoothOn(context)

        assertThat(isUserSupported(resolver)).isTrue()
    }
@@ -260,6 +262,33 @@ class AutoOnFeatureTest {
        assertThat(timer).isNotNull()
    }

    @Test
    fun apiSetUserEnableToFalse_whenEnabled_broadcastIntent() {
        setUserEnabled(false)

        assertThat(shadowOf(context as Application).getBroadcastIntents().get(0)).run {
            hasAction(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED)
            hasFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
            extras()
                .integer(BluetoothAdapter.EXTRA_AUTO_ON_STATE)
                .isEqualTo(BluetoothAdapter.AUTO_ON_STATE_OFF)
        }
    }

    @Test
    fun apiSetUserEnableToTrue_whenDisabled_broadcastIntent() {
        disableUserSettings()
        setUserEnabled(true)

        assertThat(shadowOf(context as Application).getBroadcastIntents().get(0)).run {
            hasAction(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED)
            hasFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
            extras()
                .integer(BluetoothAdapter.EXTRA_AUTO_ON_STATE)
                .isEqualTo(BluetoothAdapter.AUTO_ON_STATE_ON)
        }
    }

    @Test
    fun pause_whenIdle_noTimeSave() {
        pause()
Loading