Loading service/src/AutoOnFeature.kt +0 −87 Original line number Original line Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.content.ContentResolver import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.content.IntentFilter import android.content.IntentFilter import android.database.ContentObserver import android.os.Build import android.os.Build import android.os.Handler import android.os.Handler import android.os.Looper import android.os.Looper Loading Loading @@ -142,16 +141,6 @@ public fun setUserEnabled( resetAutoOnTimerForUser(looper, context, state, callback_on) resetAutoOnTimerForUser(looper, context, state, callback_on) } } // Listener is needed because code should be actionable prior to V API release public fun registerHiddenApiListener( looper: Looper, context: Context, state: BluetoothAdapterState, callback_on: () -> Unit ) { HiddenApiListener.registerUser(looper, context, state, callback_on) } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////// PRIVATE METHODS ///////////////////////////////////////// ////////////////////////////////////////// PRIVATE METHODS ///////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -312,79 +301,3 @@ private fun setFeatureEnabledForUserUnchecked(context: Context, status: Boolean) } } return ret return ret } } // Listener is needed because code should be actionable prior to V API release @VisibleForTesting internal class HiddenApiListener private constructor( looper: Looper, private val context: Context, state: BluetoothAdapterState, callback_on: () -> Unit ) { companion object { @VisibleForTesting internal var listener: HiddenApiListener? = null fun registerUser( looper: Looper, context: Context, state: BluetoothAdapterState, callback_on: () -> Unit ) { // Remove observer on previous user listener?.remove() listener = HiddenApiListener(looper, context, state, callback_on) } } private val handler = Handler(looper) private val observer = object : ContentObserver(handler) { override fun onChange(selfChange: Boolean) { var previousState = featureState var newState = Settings.Secure.getInt(context.contentResolver, USER_SETTINGS_KEY, -1) featureState = newState if (previousState == newState) { Log.d(TAG, "HiddenApi: State is unchanged: ${newState}") return } if (previousState == -1) { Log.d(TAG, "HiddenApi: Feature default state got setup to ${newState}") return } Log.d(TAG, "HiddenApi: Feature state change from ${previousState} to ${newState}") Counter.logIncrement("bluetooth.value_auto_on_hidden_usage") Counter.logIncrement( if (newState == 1) "bluetooth.value_auto_on_enabled" else "bluetooth.value_auto_on_disabled" ) resetAutoOnTimerForUser(looper, context, state, callback_on) } } private var featureState = Settings.Secure.getInt(context.contentResolver, USER_SETTINGS_KEY, -1) init { val notifyForDescendants = false context.contentResolver.registerContentObserver( Settings.Secure.getUriFor(USER_SETTINGS_KEY), notifyForDescendants, observer ) } @VisibleForTesting internal fun remove() { context.contentResolver.unregisterContentObserver(observer) handler.removeCallbacksAndMessages(null) } } service/src/AutoOnFeatureTest.kt +0 −107 Original line number Original line Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.provider.Settings import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider import androidx.test.ext.truth.content.IntentSubject.assertThat import androidx.test.ext.truth.content.IntentSubject.assertThat import com.android.server.bluetooth.BluetoothAdapterState import com.android.server.bluetooth.BluetoothAdapterState import com.android.server.bluetooth.HiddenApiListener import com.android.server.bluetooth.Log import com.android.server.bluetooth.Log import com.android.server.bluetooth.Timer import com.android.server.bluetooth.Timer import com.android.server.bluetooth.USER_SETTINGS_KEY import com.android.server.bluetooth.USER_SETTINGS_KEY Loading @@ -35,7 +34,6 @@ import com.android.server.bluetooth.isUserEnabled import com.android.server.bluetooth.isUserSupported import com.android.server.bluetooth.isUserSupported import com.android.server.bluetooth.notifyBluetoothOn import com.android.server.bluetooth.notifyBluetoothOn import com.android.server.bluetooth.pause import com.android.server.bluetooth.pause import com.android.server.bluetooth.registerHiddenApiListener import com.android.server.bluetooth.resetAutoOnTimerForUser import com.android.server.bluetooth.resetAutoOnTimerForUser import com.android.server.bluetooth.satellite.isOn as isSatelliteModeOn import com.android.server.bluetooth.satellite.isOn as isSatelliteModeOn import com.android.server.bluetooth.satellite.test.ModeListenerTest as SatelliteListener import com.android.server.bluetooth.satellite.test.ModeListenerTest as SatelliteListener Loading @@ -58,8 +56,6 @@ import org.robolectric.Shadows.shadowOf @RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class) @kotlinx.coroutines.ExperimentalCoroutinesApi @kotlinx.coroutines.ExperimentalCoroutinesApi class AutoOnFeatureTest { class AutoOnFeatureTest { private val SETTING_URI = Settings.Secure.getUriFor(USER_SETTINGS_KEY) private val looper = Looper.getMainLooper() private val looper = Looper.getMainLooper() private val state = BluetoothAdapterState() private val state = BluetoothAdapterState() private val context = ApplicationProvider.getApplicationContext<Context>() private val context = ApplicationProvider.getApplicationContext<Context>() Loading @@ -81,9 +77,6 @@ class AutoOnFeatureTest { @After @After fun tearDown() { fun tearDown() { HiddenApiListener.listener?.let { it.remove() } HiddenApiListener.listener = null callback_count = 0 callback_count = 0 timer?.cancel() timer?.cancel() timer = null timer = null Loading Loading @@ -446,104 +439,4 @@ class AutoOnFeatureTest { expect.that(callback_count).isEqualTo(0) expect.that(callback_count).isEqualTo(0) expectStorageTime() expectStorageTime() } } @Test fun registerHiddenListener_whenNothing_isRegistered() { registerHiddenApiListener(looper, context, state, this::callback_on) assertThat(HiddenApiListener.listener).isNotNull() } @Test fun unregisterHiddenListener_whenRegistered_isNotRegistered() { registerHiddenApiListener(looper, context, state, this::callback_on) HiddenApiListener.listener?.let { it.remove() } assertThat(shadowOf(resolver).getContentObservers(SETTING_URI).size).isEqualTo(0) } @Test fun registerHiddenListener_whenAlreadyRegistered_isRegisteredOnce() { registerHiddenApiListener(looper, context, state, this::callback_on) registerHiddenApiListener(looper, context, state, this::callback_on) expect.that(shadowOf(resolver).getContentObservers(SETTING_URI).size).isEqualTo(1) expect.that(HiddenApiListener.listener).isNotNull() } @Test fun changeSettingsToDisabled_whenHiddenApiIsRegisteredandNotScheduled_isNotSchedule() { registerHiddenApiListener(looper, context, state, this::callback_on) disableUserSettings() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } @Test fun changeSettingsToDisabled_whenHiddenApiIsRegisteredandScheduled_isNotSchedule() { setupTimer() registerHiddenApiListener(looper, context, state, this::callback_on) disableUserSettings() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } @Test fun changeSettingsToEnabled_whenHiddenApiIsRegisteredandNotScheduled_isSchedule() { disableUserSettings() registerHiddenApiListener(looper, context, state, this::callback_on) enableUserSettings() expect.that(timer).isNotNull() expect.that(callback_count).isEqualTo(0) expectStorageTime() } @Test fun setSettingsToSameValue_whenHiddenApiIsRegisteredandNotScheduled_isNotSchedule() { restoreSettings() registerHiddenApiListener(looper, context, state, this::callback_on) Settings.Secure.putInt(resolver, USER_SETTINGS_KEY, -1) shadowOf(looper).idle() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } @Test fun setSettingsToEnabled_whenHiddenApiIsRegisteredandNotSupported_isNotSchedule() { restoreSettings() registerHiddenApiListener(looper, context, state, this::callback_on) enableUserSettings() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } @Test fun setSettingsToDisable_whenHiddenApiIsRegisteredandNotSupported_isNotSchedule() { // Current design will set the feature to enabled, but there is no reason to not support // having a default value to disabled restoreSettings() registerHiddenApiListener(looper, context, state, this::callback_on) disableUserSettings() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } } } service/src/com/android/server/bluetooth/BluetoothManagerService.java +0 −18 Original line number Original line Diff line number Diff line Loading @@ -1297,8 +1297,6 @@ class BluetoothManagerService { } else { } else { autoOnSetupTimer(); autoOnSetupTimer(); } } autoOnHiddenListener(); } } /** Called when switching to a different foreground user. */ /** Called when switching to a different foreground user. */ Loading Loading @@ -1908,9 +1906,6 @@ class BluetoothManagerService { } else { } else { autoOnSetupTimer(); autoOnSetupTimer(); } } autoOnHiddenListener(); break; break; case MESSAGE_USER_UNLOCKED: case MESSAGE_USER_UNLOCKED: Loading Loading @@ -2611,19 +2606,6 @@ class BluetoothManagerService { mLooper, mCurrentUserContext, mState, this::enableFromAutoOn); mLooper, mCurrentUserContext, mState, this::enableFromAutoOn); } } private void autoOnHiddenListener() { if (!mDeviceConfigAllowAutoOn) { Log.d(TAG, "No support for AutoOn feature: Not listening on hidden api"); return; } if (isAtLeastV()) { Log.d(TAG, "AutoOn feature: prevent listening on hidden api. Use proper API in V+"); return; } AutoOnFeature.registerHiddenApiListener( mLooper, mCurrentUserContext, mState, this::enableFromAutoOn); } private <T> T postAndWait(Callable<T> callable) { private <T> T postAndWait(Callable<T> callable) { FutureTask<T> task = new FutureTask(callable); FutureTask<T> task = new FutureTask(callable); Loading Loading
service/src/AutoOnFeature.kt +0 −87 Original line number Original line Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.content.ContentResolver import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.content.IntentFilter import android.content.IntentFilter import android.database.ContentObserver import android.os.Build import android.os.Build import android.os.Handler import android.os.Handler import android.os.Looper import android.os.Looper Loading Loading @@ -142,16 +141,6 @@ public fun setUserEnabled( resetAutoOnTimerForUser(looper, context, state, callback_on) resetAutoOnTimerForUser(looper, context, state, callback_on) } } // Listener is needed because code should be actionable prior to V API release public fun registerHiddenApiListener( looper: Looper, context: Context, state: BluetoothAdapterState, callback_on: () -> Unit ) { HiddenApiListener.registerUser(looper, context, state, callback_on) } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////// PRIVATE METHODS ///////////////////////////////////////// ////////////////////////////////////////// PRIVATE METHODS ///////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -312,79 +301,3 @@ private fun setFeatureEnabledForUserUnchecked(context: Context, status: Boolean) } } return ret return ret } } // Listener is needed because code should be actionable prior to V API release @VisibleForTesting internal class HiddenApiListener private constructor( looper: Looper, private val context: Context, state: BluetoothAdapterState, callback_on: () -> Unit ) { companion object { @VisibleForTesting internal var listener: HiddenApiListener? = null fun registerUser( looper: Looper, context: Context, state: BluetoothAdapterState, callback_on: () -> Unit ) { // Remove observer on previous user listener?.remove() listener = HiddenApiListener(looper, context, state, callback_on) } } private val handler = Handler(looper) private val observer = object : ContentObserver(handler) { override fun onChange(selfChange: Boolean) { var previousState = featureState var newState = Settings.Secure.getInt(context.contentResolver, USER_SETTINGS_KEY, -1) featureState = newState if (previousState == newState) { Log.d(TAG, "HiddenApi: State is unchanged: ${newState}") return } if (previousState == -1) { Log.d(TAG, "HiddenApi: Feature default state got setup to ${newState}") return } Log.d(TAG, "HiddenApi: Feature state change from ${previousState} to ${newState}") Counter.logIncrement("bluetooth.value_auto_on_hidden_usage") Counter.logIncrement( if (newState == 1) "bluetooth.value_auto_on_enabled" else "bluetooth.value_auto_on_disabled" ) resetAutoOnTimerForUser(looper, context, state, callback_on) } } private var featureState = Settings.Secure.getInt(context.contentResolver, USER_SETTINGS_KEY, -1) init { val notifyForDescendants = false context.contentResolver.registerContentObserver( Settings.Secure.getUriFor(USER_SETTINGS_KEY), notifyForDescendants, observer ) } @VisibleForTesting internal fun remove() { context.contentResolver.unregisterContentObserver(observer) handler.removeCallbacksAndMessages(null) } }
service/src/AutoOnFeatureTest.kt +0 −107 Original line number Original line Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.provider.Settings import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider import androidx.test.ext.truth.content.IntentSubject.assertThat import androidx.test.ext.truth.content.IntentSubject.assertThat import com.android.server.bluetooth.BluetoothAdapterState import com.android.server.bluetooth.BluetoothAdapterState import com.android.server.bluetooth.HiddenApiListener import com.android.server.bluetooth.Log import com.android.server.bluetooth.Log import com.android.server.bluetooth.Timer import com.android.server.bluetooth.Timer import com.android.server.bluetooth.USER_SETTINGS_KEY import com.android.server.bluetooth.USER_SETTINGS_KEY Loading @@ -35,7 +34,6 @@ import com.android.server.bluetooth.isUserEnabled import com.android.server.bluetooth.isUserSupported import com.android.server.bluetooth.isUserSupported import com.android.server.bluetooth.notifyBluetoothOn import com.android.server.bluetooth.notifyBluetoothOn import com.android.server.bluetooth.pause import com.android.server.bluetooth.pause import com.android.server.bluetooth.registerHiddenApiListener import com.android.server.bluetooth.resetAutoOnTimerForUser import com.android.server.bluetooth.resetAutoOnTimerForUser import com.android.server.bluetooth.satellite.isOn as isSatelliteModeOn import com.android.server.bluetooth.satellite.isOn as isSatelliteModeOn import com.android.server.bluetooth.satellite.test.ModeListenerTest as SatelliteListener import com.android.server.bluetooth.satellite.test.ModeListenerTest as SatelliteListener Loading @@ -58,8 +56,6 @@ import org.robolectric.Shadows.shadowOf @RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class) @kotlinx.coroutines.ExperimentalCoroutinesApi @kotlinx.coroutines.ExperimentalCoroutinesApi class AutoOnFeatureTest { class AutoOnFeatureTest { private val SETTING_URI = Settings.Secure.getUriFor(USER_SETTINGS_KEY) private val looper = Looper.getMainLooper() private val looper = Looper.getMainLooper() private val state = BluetoothAdapterState() private val state = BluetoothAdapterState() private val context = ApplicationProvider.getApplicationContext<Context>() private val context = ApplicationProvider.getApplicationContext<Context>() Loading @@ -81,9 +77,6 @@ class AutoOnFeatureTest { @After @After fun tearDown() { fun tearDown() { HiddenApiListener.listener?.let { it.remove() } HiddenApiListener.listener = null callback_count = 0 callback_count = 0 timer?.cancel() timer?.cancel() timer = null timer = null Loading Loading @@ -446,104 +439,4 @@ class AutoOnFeatureTest { expect.that(callback_count).isEqualTo(0) expect.that(callback_count).isEqualTo(0) expectStorageTime() expectStorageTime() } } @Test fun registerHiddenListener_whenNothing_isRegistered() { registerHiddenApiListener(looper, context, state, this::callback_on) assertThat(HiddenApiListener.listener).isNotNull() } @Test fun unregisterHiddenListener_whenRegistered_isNotRegistered() { registerHiddenApiListener(looper, context, state, this::callback_on) HiddenApiListener.listener?.let { it.remove() } assertThat(shadowOf(resolver).getContentObservers(SETTING_URI).size).isEqualTo(0) } @Test fun registerHiddenListener_whenAlreadyRegistered_isRegisteredOnce() { registerHiddenApiListener(looper, context, state, this::callback_on) registerHiddenApiListener(looper, context, state, this::callback_on) expect.that(shadowOf(resolver).getContentObservers(SETTING_URI).size).isEqualTo(1) expect.that(HiddenApiListener.listener).isNotNull() } @Test fun changeSettingsToDisabled_whenHiddenApiIsRegisteredandNotScheduled_isNotSchedule() { registerHiddenApiListener(looper, context, state, this::callback_on) disableUserSettings() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } @Test fun changeSettingsToDisabled_whenHiddenApiIsRegisteredandScheduled_isNotSchedule() { setupTimer() registerHiddenApiListener(looper, context, state, this::callback_on) disableUserSettings() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } @Test fun changeSettingsToEnabled_whenHiddenApiIsRegisteredandNotScheduled_isSchedule() { disableUserSettings() registerHiddenApiListener(looper, context, state, this::callback_on) enableUserSettings() expect.that(timer).isNotNull() expect.that(callback_count).isEqualTo(0) expectStorageTime() } @Test fun setSettingsToSameValue_whenHiddenApiIsRegisteredandNotScheduled_isNotSchedule() { restoreSettings() registerHiddenApiListener(looper, context, state, this::callback_on) Settings.Secure.putInt(resolver, USER_SETTINGS_KEY, -1) shadowOf(looper).idle() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } @Test fun setSettingsToEnabled_whenHiddenApiIsRegisteredandNotSupported_isNotSchedule() { restoreSettings() registerHiddenApiListener(looper, context, state, this::callback_on) enableUserSettings() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } @Test fun setSettingsToDisable_whenHiddenApiIsRegisteredandNotSupported_isNotSchedule() { // Current design will set the feature to enabled, but there is no reason to not support // having a default value to disabled restoreSettings() registerHiddenApiListener(looper, context, state, this::callback_on) disableUserSettings() expect.that(timer).isNull() expect.that(callback_count).isEqualTo(0) expectNoStorageTime() } } }
service/src/com/android/server/bluetooth/BluetoothManagerService.java +0 −18 Original line number Original line Diff line number Diff line Loading @@ -1297,8 +1297,6 @@ class BluetoothManagerService { } else { } else { autoOnSetupTimer(); autoOnSetupTimer(); } } autoOnHiddenListener(); } } /** Called when switching to a different foreground user. */ /** Called when switching to a different foreground user. */ Loading Loading @@ -1908,9 +1906,6 @@ class BluetoothManagerService { } else { } else { autoOnSetupTimer(); autoOnSetupTimer(); } } autoOnHiddenListener(); break; break; case MESSAGE_USER_UNLOCKED: case MESSAGE_USER_UNLOCKED: Loading Loading @@ -2611,19 +2606,6 @@ class BluetoothManagerService { mLooper, mCurrentUserContext, mState, this::enableFromAutoOn); mLooper, mCurrentUserContext, mState, this::enableFromAutoOn); } } private void autoOnHiddenListener() { if (!mDeviceConfigAllowAutoOn) { Log.d(TAG, "No support for AutoOn feature: Not listening on hidden api"); return; } if (isAtLeastV()) { Log.d(TAG, "AutoOn feature: prevent listening on hidden api. Use proper API in V+"); return; } AutoOnFeature.registerHiddenApiListener( mLooper, mCurrentUserContext, mState, this::enableFromAutoOn); } private <T> T postAndWait(Callable<T> callable) { private <T> T postAndWait(Callable<T> callable) { FutureTask<T> task = new FutureTask(callable); FutureTask<T> task = new FutureTask(callable); Loading