Loading packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt +3 −2 Original line number Diff line number Diff line Loading @@ -52,8 +52,8 @@ constructor( eventTimeMillis: Long, batteryState: BatteryState ) { if (batteryState.isPresent) { stylusUsiPowerUi.updateBatteryState(batteryState) if (batteryState.isPresent && batteryState.capacity > 0f) { stylusUsiPowerUi.updateBatteryState(deviceId, batteryState) } } Loading @@ -61,6 +61,7 @@ constructor( if (!featureFlags.isEnabled(Flags.ENABLE_USI_BATTERY_NOTIFICATIONS)) return if (!hostDeviceSupportsStylusInput()) return stylusUsiPowerUi.init() stylusManager.registerCallback(this) stylusManager.startListener() } Loading packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt +38 −9 Original line number Diff line number Diff line Loading @@ -18,17 +18,21 @@ package com.android.systemui.stylus import android.Manifest import android.app.PendingIntent import android.content.ActivityNotFoundException import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.hardware.BatteryState import android.hardware.input.InputManager import android.os.Bundle import android.os.Handler import android.os.UserHandle import android.util.Log import android.view.InputDevice import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.android.internal.annotations.VisibleForTesting import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background Loading @@ -53,6 +57,7 @@ constructor( // These values must only be accessed on the handler. private var batteryCapacity = 1.0f private var suppressed = false private var inputDeviceId: Int? = null fun init() { val filter = Loading Loading @@ -87,10 +92,12 @@ constructor( } } fun updateBatteryState(batteryState: BatteryState) { fun updateBatteryState(deviceId: Int, batteryState: BatteryState) { handler.post updateBattery@{ if (batteryState.capacity == batteryCapacity) return@updateBattery if (batteryState.capacity == batteryCapacity || batteryState.capacity <= 0f) return@updateBattery inputDeviceId = deviceId batteryCapacity = batteryState.capacity refresh() } Loading Loading @@ -150,23 +157,41 @@ constructor( } private fun getPendingBroadcast(action: String): PendingIntent? { return PendingIntent.getBroadcastAsUser( return PendingIntent.getBroadcast( context, 0, Intent(action), Intent(action).setPackage(context.packageName), PendingIntent.FLAG_IMMUTABLE, UserHandle.CURRENT ) } private val receiver: BroadcastReceiver = @VisibleForTesting internal val receiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { ACTION_DISMISSED_LOW_BATTERY -> updateSuppression(true) ACTION_CLICKED_LOW_BATTERY -> { updateSuppression(true) // TODO(b/261584943): open USI device details page if (inputDeviceId == null) return val args = Bundle() args.putInt(KEY_DEVICE_INPUT_ID, inputDeviceId!!) try { context.startActivity( Intent(ACTION_STYLUS_USI_DETAILS) .putExtra(KEY_SETTINGS_FRAGMENT_ARGS, args) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ) } catch (e: ActivityNotFoundException) { // In the rare scenario where the Settings app manifest doesn't contain // the USI details activity, ignore the intent. Log.e( StylusUsiPowerUI::class.java.simpleName, "Cannot open USI details page." ) } } } } Loading @@ -179,7 +204,11 @@ constructor( private val USI_NOTIFICATION_ID = R.string.stylus_battery_low_percentage private const val ACTION_DISMISSED_LOW_BATTERY = "StylusUsiPowerUI.dismiss" private const val ACTION_CLICKED_LOW_BATTERY = "StylusUsiPowerUI.click" @VisibleForTesting const val ACTION_DISMISSED_LOW_BATTERY = "StylusUsiPowerUI.dismiss" @VisibleForTesting const val ACTION_CLICKED_LOW_BATTERY = "StylusUsiPowerUI.click" @VisibleForTesting const val ACTION_STYLUS_USI_DETAILS = "com.android.settings.STYLUS_USI_DETAILS_SETTINGS" @VisibleForTesting const val KEY_DEVICE_INPUT_ID = "device_input_id" @VisibleForTesting const val KEY_SETTINGS_FRAGMENT_ARGS = ":settings:show_fragment_args" } } packages/SystemUI/tests/src/com/android/systemui/stylus/FixedCapacityBatteryState.kt 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.stylus import android.hardware.BatteryState class FixedCapacityBatteryState(private val capacity: Float) : BatteryState() { override fun getCapacity() = capacity override fun getStatus() = 0 override fun isPresent() = true } packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt +19 −4 Original line number Diff line number Diff line Loading @@ -84,6 +84,13 @@ class StylusUsiPowerStartableTest : SysuiTestCase() { verifyZeroInteractions(stylusManager) } @Test fun start_initStylusUsiPowerUi() { startable.start() verify(stylusUsiPowerUi, times(1)).init() } @Test fun onStylusBluetoothConnected_refreshesNotification() { startable.onStylusBluetoothConnected(STYLUS_DEVICE_ID, "ANY") Loading @@ -99,13 +106,21 @@ class StylusUsiPowerStartableTest : SysuiTestCase() { } @Test fun onStylusUsiBatteryStateChanged_batteryPresent_refreshesNotification() { val batteryState = mock(BatteryState::class.java) whenever(batteryState.isPresent).thenReturn(true) fun onStylusUsiBatteryStateChanged_batteryPresentValidCapacity_refreshesNotification() { val batteryState = FixedCapacityBatteryState(0.1f) startable.onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState) verify(stylusUsiPowerUi, times(1)).updateBatteryState(batteryState) verify(stylusUsiPowerUi, times(1)).updateBatteryState(STYLUS_DEVICE_ID, batteryState) } @Test fun onStylusUsiBatteryStateChanged_batteryPresentInvalidCapacity_noop() { val batteryState = FixedCapacityBatteryState(0f) startable.onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState) verifyNoMoreInteractions(stylusUsiPowerUi) } @Test Loading packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt +56 −17 Original line number Diff line number Diff line Loading @@ -17,8 +17,11 @@ package com.android.systemui.stylus import android.app.Notification import android.hardware.BatteryState import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.hardware.input.InputManager import android.os.Bundle import android.os.Handler import android.testing.AndroidTestingRunner import android.view.InputDevice Loading @@ -27,8 +30,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertEquals import org.junit.Before import org.junit.Ignore Loading @@ -37,7 +42,10 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.doNothing import org.mockito.Mockito.inOrder import org.mockito.Mockito.never import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions Loading @@ -53,11 +61,16 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Captor lateinit var notificationCaptor: ArgumentCaptor<Notification> private lateinit var stylusUsiPowerUi: StylusUsiPowerUI private lateinit var broadcastReceiver: BroadcastReceiver private lateinit var contextSpy: Context @Before fun setUp() { MockitoAnnotations.initMocks(this) contextSpy = spy(mContext) doNothing().whenever(contextSpy).startActivity(any()) whenever(handler.post(any())).thenAnswer { (it.arguments[0] as Runnable).run() true Loading @@ -68,12 +81,20 @@ class StylusUsiPowerUiTest : SysuiTestCase() { whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true) // whenever(btStylusDevice.bluetoothAddress).thenReturn("SO:ME:AD:DR:ES") stylusUsiPowerUi = StylusUsiPowerUI(mContext, notificationManager, inputManager, handler) stylusUsiPowerUi = StylusUsiPowerUI(contextSpy, notificationManager, inputManager, handler) broadcastReceiver = stylusUsiPowerUi.receiver } @Test fun updateBatteryState_capacityZero_noop() { stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0f)) verifyNoMoreInteractions(notificationManager) } @Test fun updateBatteryState_capacityBelowThreshold_notifies() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) verify(notificationManager, times(1)) .notify(eq(R.string.stylus_battery_low_percentage), any()) Loading @@ -82,7 +103,7 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateBatteryState_capacityAboveThreshold_cancelsNotificattion() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.8f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.8f)) verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low_percentage) verifyNoMoreInteractions(notificationManager) Loading @@ -90,8 +111,8 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateBatteryState_existingNotification_capacityAboveThreshold_cancelsNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.8f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.8f)) inOrder(notificationManager).let { it.verify(notificationManager, times(1)) Loading @@ -103,8 +124,8 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateBatteryState_existingNotification_capacityBelowThreshold_updatesNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.15f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.15f)) verify(notificationManager, times(2)) .notify(eq(R.string.stylus_battery_low_percentage), notificationCaptor.capture()) Loading @@ -121,9 +142,9 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateBatteryState_capacityAboveThenBelowThreshold_hidesThenShowsNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.5f)) stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.5f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) inOrder(notificationManager).let { it.verify(notificationManager, times(1)) Loading @@ -145,7 +166,7 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateSuppression_existingNotification_cancelsNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateSuppression(true) Loading @@ -170,7 +191,7 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test @Ignore("TODO(b/257936830): get bt address once input api available") fun refresh_hasConnectedBluetoothStylus_existingNotification_cancelsNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(0)) stylusUsiPowerUi.refresh() Loading @@ -178,9 +199,27 @@ class StylusUsiPowerUiTest : SysuiTestCase() { verify(notificationManager).cancel(R.string.stylus_battery_low_percentage) } class FixedCapacityBatteryState(private val capacity: Float) : BatteryState() { override fun getCapacity() = capacity override fun getStatus() = 0 override fun isPresent() = true @Test fun broadcastReceiver_clicked_hasInputDeviceId_startsUsiDetailsActivity() { val intent = Intent(StylusUsiPowerUI.ACTION_CLICKED_LOW_BATTERY) val activityIntentCaptor = argumentCaptor<Intent>() stylusUsiPowerUi.updateBatteryState(1, FixedCapacityBatteryState(0.15f)) broadcastReceiver.onReceive(contextSpy, intent) verify(contextSpy, times(1)).startActivity(activityIntentCaptor.capture()) assertThat(activityIntentCaptor.value.action) .isEqualTo(StylusUsiPowerUI.ACTION_STYLUS_USI_DETAILS) val args = activityIntentCaptor.value.getExtra(StylusUsiPowerUI.KEY_SETTINGS_FRAGMENT_ARGS) as Bundle assertThat(args.getInt(StylusUsiPowerUI.KEY_DEVICE_INPUT_ID)).isEqualTo(1) } @Test fun broadcastReceiver_clicked_nullInputDeviceId_doesNotStartActivity() { val intent = Intent(StylusUsiPowerUI.ACTION_CLICKED_LOW_BATTERY) broadcastReceiver.onReceive(contextSpy, intent) verify(contextSpy, never()).startActivity(any()) } } Loading
packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt +3 −2 Original line number Diff line number Diff line Loading @@ -52,8 +52,8 @@ constructor( eventTimeMillis: Long, batteryState: BatteryState ) { if (batteryState.isPresent) { stylusUsiPowerUi.updateBatteryState(batteryState) if (batteryState.isPresent && batteryState.capacity > 0f) { stylusUsiPowerUi.updateBatteryState(deviceId, batteryState) } } Loading @@ -61,6 +61,7 @@ constructor( if (!featureFlags.isEnabled(Flags.ENABLE_USI_BATTERY_NOTIFICATIONS)) return if (!hostDeviceSupportsStylusInput()) return stylusUsiPowerUi.init() stylusManager.registerCallback(this) stylusManager.startListener() } Loading
packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt +38 −9 Original line number Diff line number Diff line Loading @@ -18,17 +18,21 @@ package com.android.systemui.stylus import android.Manifest import android.app.PendingIntent import android.content.ActivityNotFoundException import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.hardware.BatteryState import android.hardware.input.InputManager import android.os.Bundle import android.os.Handler import android.os.UserHandle import android.util.Log import android.view.InputDevice import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.android.internal.annotations.VisibleForTesting import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background Loading @@ -53,6 +57,7 @@ constructor( // These values must only be accessed on the handler. private var batteryCapacity = 1.0f private var suppressed = false private var inputDeviceId: Int? = null fun init() { val filter = Loading Loading @@ -87,10 +92,12 @@ constructor( } } fun updateBatteryState(batteryState: BatteryState) { fun updateBatteryState(deviceId: Int, batteryState: BatteryState) { handler.post updateBattery@{ if (batteryState.capacity == batteryCapacity) return@updateBattery if (batteryState.capacity == batteryCapacity || batteryState.capacity <= 0f) return@updateBattery inputDeviceId = deviceId batteryCapacity = batteryState.capacity refresh() } Loading Loading @@ -150,23 +157,41 @@ constructor( } private fun getPendingBroadcast(action: String): PendingIntent? { return PendingIntent.getBroadcastAsUser( return PendingIntent.getBroadcast( context, 0, Intent(action), Intent(action).setPackage(context.packageName), PendingIntent.FLAG_IMMUTABLE, UserHandle.CURRENT ) } private val receiver: BroadcastReceiver = @VisibleForTesting internal val receiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { ACTION_DISMISSED_LOW_BATTERY -> updateSuppression(true) ACTION_CLICKED_LOW_BATTERY -> { updateSuppression(true) // TODO(b/261584943): open USI device details page if (inputDeviceId == null) return val args = Bundle() args.putInt(KEY_DEVICE_INPUT_ID, inputDeviceId!!) try { context.startActivity( Intent(ACTION_STYLUS_USI_DETAILS) .putExtra(KEY_SETTINGS_FRAGMENT_ARGS, args) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ) } catch (e: ActivityNotFoundException) { // In the rare scenario where the Settings app manifest doesn't contain // the USI details activity, ignore the intent. Log.e( StylusUsiPowerUI::class.java.simpleName, "Cannot open USI details page." ) } } } } Loading @@ -179,7 +204,11 @@ constructor( private val USI_NOTIFICATION_ID = R.string.stylus_battery_low_percentage private const val ACTION_DISMISSED_LOW_BATTERY = "StylusUsiPowerUI.dismiss" private const val ACTION_CLICKED_LOW_BATTERY = "StylusUsiPowerUI.click" @VisibleForTesting const val ACTION_DISMISSED_LOW_BATTERY = "StylusUsiPowerUI.dismiss" @VisibleForTesting const val ACTION_CLICKED_LOW_BATTERY = "StylusUsiPowerUI.click" @VisibleForTesting const val ACTION_STYLUS_USI_DETAILS = "com.android.settings.STYLUS_USI_DETAILS_SETTINGS" @VisibleForTesting const val KEY_DEVICE_INPUT_ID = "device_input_id" @VisibleForTesting const val KEY_SETTINGS_FRAGMENT_ARGS = ":settings:show_fragment_args" } }
packages/SystemUI/tests/src/com/android/systemui/stylus/FixedCapacityBatteryState.kt 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.stylus import android.hardware.BatteryState class FixedCapacityBatteryState(private val capacity: Float) : BatteryState() { override fun getCapacity() = capacity override fun getStatus() = 0 override fun isPresent() = true }
packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt +19 −4 Original line number Diff line number Diff line Loading @@ -84,6 +84,13 @@ class StylusUsiPowerStartableTest : SysuiTestCase() { verifyZeroInteractions(stylusManager) } @Test fun start_initStylusUsiPowerUi() { startable.start() verify(stylusUsiPowerUi, times(1)).init() } @Test fun onStylusBluetoothConnected_refreshesNotification() { startable.onStylusBluetoothConnected(STYLUS_DEVICE_ID, "ANY") Loading @@ -99,13 +106,21 @@ class StylusUsiPowerStartableTest : SysuiTestCase() { } @Test fun onStylusUsiBatteryStateChanged_batteryPresent_refreshesNotification() { val batteryState = mock(BatteryState::class.java) whenever(batteryState.isPresent).thenReturn(true) fun onStylusUsiBatteryStateChanged_batteryPresentValidCapacity_refreshesNotification() { val batteryState = FixedCapacityBatteryState(0.1f) startable.onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState) verify(stylusUsiPowerUi, times(1)).updateBatteryState(batteryState) verify(stylusUsiPowerUi, times(1)).updateBatteryState(STYLUS_DEVICE_ID, batteryState) } @Test fun onStylusUsiBatteryStateChanged_batteryPresentInvalidCapacity_noop() { val batteryState = FixedCapacityBatteryState(0f) startable.onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState) verifyNoMoreInteractions(stylusUsiPowerUi) } @Test Loading
packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt +56 −17 Original line number Diff line number Diff line Loading @@ -17,8 +17,11 @@ package com.android.systemui.stylus import android.app.Notification import android.hardware.BatteryState import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.hardware.input.InputManager import android.os.Bundle import android.os.Handler import android.testing.AndroidTestingRunner import android.view.InputDevice Loading @@ -27,8 +30,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertEquals import org.junit.Before import org.junit.Ignore Loading @@ -37,7 +42,10 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.doNothing import org.mockito.Mockito.inOrder import org.mockito.Mockito.never import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions Loading @@ -53,11 +61,16 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Captor lateinit var notificationCaptor: ArgumentCaptor<Notification> private lateinit var stylusUsiPowerUi: StylusUsiPowerUI private lateinit var broadcastReceiver: BroadcastReceiver private lateinit var contextSpy: Context @Before fun setUp() { MockitoAnnotations.initMocks(this) contextSpy = spy(mContext) doNothing().whenever(contextSpy).startActivity(any()) whenever(handler.post(any())).thenAnswer { (it.arguments[0] as Runnable).run() true Loading @@ -68,12 +81,20 @@ class StylusUsiPowerUiTest : SysuiTestCase() { whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true) // whenever(btStylusDevice.bluetoothAddress).thenReturn("SO:ME:AD:DR:ES") stylusUsiPowerUi = StylusUsiPowerUI(mContext, notificationManager, inputManager, handler) stylusUsiPowerUi = StylusUsiPowerUI(contextSpy, notificationManager, inputManager, handler) broadcastReceiver = stylusUsiPowerUi.receiver } @Test fun updateBatteryState_capacityZero_noop() { stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0f)) verifyNoMoreInteractions(notificationManager) } @Test fun updateBatteryState_capacityBelowThreshold_notifies() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) verify(notificationManager, times(1)) .notify(eq(R.string.stylus_battery_low_percentage), any()) Loading @@ -82,7 +103,7 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateBatteryState_capacityAboveThreshold_cancelsNotificattion() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.8f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.8f)) verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low_percentage) verifyNoMoreInteractions(notificationManager) Loading @@ -90,8 +111,8 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateBatteryState_existingNotification_capacityAboveThreshold_cancelsNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.8f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.8f)) inOrder(notificationManager).let { it.verify(notificationManager, times(1)) Loading @@ -103,8 +124,8 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateBatteryState_existingNotification_capacityBelowThreshold_updatesNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.15f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.15f)) verify(notificationManager, times(2)) .notify(eq(R.string.stylus_battery_low_percentage), notificationCaptor.capture()) Loading @@ -121,9 +142,9 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateBatteryState_capacityAboveThenBelowThreshold_hidesThenShowsNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.5f)) stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.5f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) inOrder(notificationManager).let { it.verify(notificationManager, times(1)) Loading @@ -145,7 +166,7 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test fun updateSuppression_existingNotification_cancelsNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateSuppression(true) Loading @@ -170,7 +191,7 @@ class StylusUsiPowerUiTest : SysuiTestCase() { @Test @Ignore("TODO(b/257936830): get bt address once input api available") fun refresh_hasConnectedBluetoothStylus_existingNotification_cancelsNotification() { stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f)) whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(0)) stylusUsiPowerUi.refresh() Loading @@ -178,9 +199,27 @@ class StylusUsiPowerUiTest : SysuiTestCase() { verify(notificationManager).cancel(R.string.stylus_battery_low_percentage) } class FixedCapacityBatteryState(private val capacity: Float) : BatteryState() { override fun getCapacity() = capacity override fun getStatus() = 0 override fun isPresent() = true @Test fun broadcastReceiver_clicked_hasInputDeviceId_startsUsiDetailsActivity() { val intent = Intent(StylusUsiPowerUI.ACTION_CLICKED_LOW_BATTERY) val activityIntentCaptor = argumentCaptor<Intent>() stylusUsiPowerUi.updateBatteryState(1, FixedCapacityBatteryState(0.15f)) broadcastReceiver.onReceive(contextSpy, intent) verify(contextSpy, times(1)).startActivity(activityIntentCaptor.capture()) assertThat(activityIntentCaptor.value.action) .isEqualTo(StylusUsiPowerUI.ACTION_STYLUS_USI_DETAILS) val args = activityIntentCaptor.value.getExtra(StylusUsiPowerUI.KEY_SETTINGS_FRAGMENT_ARGS) as Bundle assertThat(args.getInt(StylusUsiPowerUI.KEY_DEVICE_INPUT_ID)).isEqualTo(1) } @Test fun broadcastReceiver_clicked_nullInputDeviceId_doesNotStartActivity() { val intent = Intent(StylusUsiPowerUI.ACTION_CLICKED_LOW_BATTERY) broadcastReceiver.onReceive(contextSpy, intent) verify(contextSpy, never()).startActivity(any()) } }