diff options
4 files changed, 282 insertions, 9 deletions
diff --git a/packages/SystemUI/res/drawable/qs_flashlight_icon_off.xml b/packages/SystemUI/res/drawable/qs_flashlight_icon_off.xml new file mode 100644 index 000000000000..157e67a6e8e2 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_flashlight_icon_off.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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 + --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="417" + android:propertyName="pathData" + android:startOffset="0" + android:valueFrom="M0 2.02 C0.42,2.02 0.77,1.88 1.05,1.59 C1.35,1.29 1.5,0.94 1.5,0.52 C1.5,0.1 1.35,-0.25 1.05,-0.53 C0.77,-0.83 0.42,-0.98 0,-0.98 C-0.42,-0.98 -0.78,-0.83 -1.08,-0.53 C-1.36,-0.25 -1.5,0.1 -1.5,0.52 C-1.5,0.94 -1.36,1.29 -1.08,1.59 C-0.78,1.88 -0.42,2.02 0,2.02c M0 8.62 C-0.42,8.62 -2.78,8.82 -3.07,8.54 C-3.36,8.24 -3.37,-1.87 -3.37,-2.28 C-4.25,-2.69 -4.29,-5.2 -4.01,-5.48 C-3.71,-5.78 -0.42,-5.75 0,-5.75 C0.42,-5.75 4.39,-5.78 4.36,-5.36 C4.22,-2.97 4.47,-3.03 3.34,-1.78 C3.07,-1.48 3.32,8.21 3.02,8.51 C2.74,8.79 0.42,8.62 0,8.62c " + android:valueTo="M0 3 C0.42,3 0.77,2.86 1.05,2.58 C1.35,2.28 1.5,1.92 1.5,1.5 C1.5,1.08 1.35,0.73 1.05,0.45 C0.77,0.15 0.42,0 0,0 C-0.42,0 -0.78,0.15 -1.08,0.45 C-1.36,0.73 -1.5,1.08 -1.5,1.5 C-1.5,1.92 -1.36,2.28 -1.08,2.58 C-0.78,2.86 -0.42,3 0,3c M0 8.62 C-0.42,8.62 -2.24,8.83 -2.54,8.55 C-2.83,8.25 -2.86,9.1 -2.86,8.69 C-2.86,8.27 -3.02,8.85 -2.74,8.57 C-2.44,8.26 -0.43,8.31 -0.02,8.31 C0.4,8.31 2.4,8.17 2.68,8.47 C2.98,8.75 2.93,8.33 2.93,8.75 C2.93,9.17 3.32,8.21 3.02,8.51 C2.74,8.79 0.42,8.62 0,8.62c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.1,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="1000" + android:propertyName="translateX" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType" /> + </set> + </aapt:attr> + </target> + <aapt:attr name="android:drawable"> + <vector + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <group android:name="_R_G"> + <group + android:name="_R_G_L_1_G" + android:pivotY="24" + android:scaleX="0.33332999999999996" + android:scaleY="0.33332999999999996" + android:translateX="12" + android:translateY="-4"> + <path + android:name="_R_G_L_1_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#1f1f1f" + android:fillType="nonZero" + android:pathData=" M-12 -15 C-12,-15 12,-15 12,-15 C12,-15 12,-13.8 12,-13.8 C12,-13.8 6,-4.8 6,-4.8 C6,-4.8 6,24 6,24 C6,24 -6,24 -6,24 C-6,24 -6,-4.8 -6,-4.8 C-6,-4.8 -12,-13.8 -12,-13.8 C-12,-13.8 -12,-15 -12,-15c M12 -21 C12,-21 -12,-21 -12,-21 C-12,-21 -12,-24 -12,-24 C-12,-24 12,-24 12,-24 C12,-24 12,-21 12,-21c M-12 -3 C-12,-3 -12,30 -12,30 C-12,30 12,30 12,30 C12,30 12,-3 12,-3 C12,-3 18,-12 18,-12 C18,-12 18,-30 18,-30 C18,-30 -18,-30 -18,-30 C-18,-30 -18,-12 -18,-12 C-18,-12 -12,-3 -12,-3c " /> + </group> + <group + android:name="_R_G_L_0_G" + android:translateX="12" + android:translateY="12"> + <path + android:name="_R_G_L_0_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#1f1f1f" + android:fillType="nonZero" + android:pathData=" M0 2.02 C0.42,2.02 0.77,1.88 1.05,1.59 C1.35,1.29 1.5,0.94 1.5,0.52 C1.5,0.1 1.35,-0.25 1.05,-0.53 C0.77,-0.83 0.42,-0.98 0,-0.98 C-0.42,-0.98 -0.78,-0.83 -1.08,-0.53 C-1.36,-0.25 -1.5,0.1 -1.5,0.52 C-1.5,0.94 -1.36,1.29 -1.08,1.59 C-0.78,1.88 -0.42,2.02 0,2.02c " /> + </group> + </group> + <group android:name="time_group" /> + </vector> + </aapt:attr> +</animated-vector> diff --git a/packages/SystemUI/res/drawable/qs_flashlight_icon_on.xml b/packages/SystemUI/res/drawable/qs_flashlight_icon_on.xml new file mode 100644 index 000000000000..22f5e00dad69 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_flashlight_icon_on.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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 + --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="417" + android:propertyName="pathData" + android:startOffset="0" + android:valueFrom="M0 3 C0.42,3 0.77,2.86 1.05,2.58 C1.35,2.28 1.5,1.92 1.5,1.5 C1.5,1.08 1.35,0.73 1.05,0.45 C0.77,0.15 0.42,0 0,0 C-0.42,0 -0.78,0.15 -1.08,0.45 C-1.36,0.73 -1.5,1.08 -1.5,1.5 C-1.5,1.92 -1.36,2.28 -1.08,2.58 C-0.78,2.86 -0.42,3 0,3c M0 8.62 C-0.42,8.62 -2.24,8.83 -2.54,8.55 C-2.83,8.25 -2.86,9.1 -2.86,8.69 C-2.86,8.27 -3.02,8.85 -2.74,8.57 C-2.44,8.26 -0.43,8.31 -0.02,8.31 C0.4,8.31 2.4,8.17 2.68,8.47 C2.98,8.75 2.93,8.33 2.93,8.75 C2.93,9.17 3.32,8.21 3.02,8.51 C2.74,8.79 0.42,8.62 0,8.62c " + android:valueTo="M0 2.02 C0.42,2.02 0.77,1.88 1.05,1.59 C1.35,1.29 1.5,0.94 1.5,0.52 C1.5,0.1 1.35,-0.25 1.05,-0.53 C0.77,-0.83 0.42,-0.98 0,-0.98 C-0.42,-0.98 -0.78,-0.83 -1.08,-0.53 C-1.36,-0.25 -1.5,0.1 -1.5,0.52 C-1.5,0.94 -1.36,1.29 -1.08,1.59 C-0.78,1.88 -0.42,2.02 0,2.02c M0 8.62 C-0.42,8.62 -2.78,8.82 -3.07,8.54 C-3.36,8.24 -3.37,-1.87 -3.37,-2.28 C-4.25,-2.69 -4.29,-5.2 -4.01,-5.48 C-3.71,-5.78 -0.42,-5.75 0,-5.75 C0.42,-5.75 4.39,-5.78 4.36,-5.36 C4.22,-2.97 4.47,-3.03 3.34,-1.78 C3.07,-1.48 3.32,8.21 3.02,8.51 C2.74,8.79 0.42,8.62 0,8.62c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.1,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="1000" + android:propertyName="translateX" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType" /> + </set> + </aapt:attr> + </target> + <aapt:attr name="android:drawable"> + <vector + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <group android:name="_R_G"> + <group + android:name="_R_G_L_1_G" + android:pivotY="24" + android:scaleX="0.33332999999999996" + android:scaleY="0.33332999999999996" + android:translateX="12" + android:translateY="-4"> + <path + android:name="_R_G_L_1_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#1f1f1f" + android:fillType="nonZero" + android:pathData=" M-12 -15 C-12,-15 12,-15 12,-15 C12,-15 12,-13.8 12,-13.8 C12,-13.8 6,-4.8 6,-4.8 C6,-4.8 6,24 6,24 C6,24 -6,24 -6,24 C-6,24 -6,-4.8 -6,-4.8 C-6,-4.8 -12,-13.8 -12,-13.8 C-12,-13.8 -12,-15 -12,-15c M12 -21 C12,-21 -12,-21 -12,-21 C-12,-21 -12,-24 -12,-24 C-12,-24 12,-24 12,-24 C12,-24 12,-21 12,-21c M-12 -3 C-12,-3 -12,30 -12,30 C-12,30 12,30 12,30 C12,30 12,-3 12,-3 C12,-3 18,-12 18,-12 C18,-12 18,-30 18,-30 C18,-30 -18,-30 -18,-30 C-18,-30 -18,-12 -18,-12 C-18,-12 -12,-3 -12,-3c " /> + </group> + <group + android:name="_R_G_L_0_G" + android:translateX="12" + android:translateY="12"> + <path + android:name="_R_G_L_0_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#1f1f1f" + android:fillType="nonZero" + android:pathData=" M0 3 C0.42,3 0.77,2.86 1.05,2.58 C1.35,2.28 1.5,1.92 1.5,1.5 C1.5,1.08 1.35,0.73 1.05,0.45 C0.77,0.15 0.42,0 0,0 C-0.42,0 -0.78,0.15 -1.08,0.45 C-1.36,0.73 -1.5,1.08 -1.5,1.5 C-1.5,1.92 -1.36,2.28 -1.08,2.58 C-0.78,2.86 -0.42,3 0,3c " /> + </group> + </group> + <group android:name="time_group" /> + </vector> + </aapt:attr> +</animated-vector> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index 73b0896b06a5..a74792687289 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -43,11 +43,12 @@ import com.android.systemui.statusbar.policy.FlashlightController; import javax.inject.Inject; -/** Quick settings tile: Control flashlight **/ +/** + * Quick settings tile: Control flashlight + **/ public class FlashlightTile extends QSTileImpl<BooleanState> implements FlashlightController.FlashlightListener { - private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_flashlight); private final FlashlightController mFlashlightController; @Inject @@ -116,19 +117,15 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements @Override protected void handleUpdateState(BooleanState state, Object arg) { - if (state.slash == null) { - state.slash = new SlashState(); - } state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label); state.secondaryLabel = ""; state.stateDescription = ""; if (!mFlashlightController.isAvailable()) { - state.icon = mIcon; - state.slash.isSlashed = true; state.secondaryLabel = mContext.getString( R.string.quick_settings_flashlight_camera_in_use); state.stateDescription = state.secondaryLabel; state.state = Tile.STATE_UNAVAILABLE; + state.icon = ResourceIcon.get(R.drawable.qs_flashlight_icon_off); return; } if (arg instanceof Boolean) { @@ -140,11 +137,11 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements } else { state.value = mFlashlightController.isEnabled(); } - state.icon = mIcon; - state.slash.isSlashed = !state.value; state.contentDescription = mContext.getString(R.string.quick_settings_flashlight_label); state.expandedAccessibilityClassName = Switch.class.getName(); state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; + state.icon = ResourceIcon.get(state.value + ? R.drawable.qs_flashlight_icon_on : R.drawable.qs_flashlight_icon_off); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt new file mode 100644 index 000000000000..d0f851bded75 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt @@ -0,0 +1,108 @@ +package com.android.systemui.qs.tiles + +import android.content.Context +import android.os.Handler +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.internal.logging.MetricsLogger +import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingManagerFake +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.qs.QSTileHost +import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.statusbar.policy.FlashlightController +import com.google.common.truth.Truth +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +@SmallTest +class FlashlightTileTest : SysuiTestCase() { + + @Mock private lateinit var mockContext: Context + + @Mock private lateinit var qsLogger: QSLogger + + @Mock private lateinit var qsHost: QSTileHost + + @Mock private lateinit var metricsLogger: MetricsLogger + + @Mock private lateinit var statusBarStateController: StatusBarStateController + + @Mock private lateinit var activityStarter: ActivityStarter + + @Mock private lateinit var flashlightController: FlashlightController + + private val uiEventLogger = UiEventLoggerFake() + private val falsingManager = FalsingManagerFake() + private lateinit var testableLooper: TestableLooper + private lateinit var tile: FlashlightTile + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + + Mockito.`when`(qsHost.context).thenReturn(mockContext) + Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) + + tile = + FlashlightTile( + qsHost, + testableLooper.looper, + Handler(testableLooper.looper), + falsingManager, + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger, + flashlightController + ) + } + + @Test + fun testIcon_whenFlashlightEnabled_isOnState() { + Mockito.`when`(flashlightController.isAvailable).thenReturn(true) + Mockito.`when`(flashlightController.isEnabled).thenReturn(true) + val state = QSTile.BooleanState() + + tile.handleUpdateState(state, /* arg= */ null) + + Truth.assertThat(state.icon) + .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_flashlight_icon_on)) + } + + @Test + fun testIcon_whenFlashlightDisabled_isOffState() { + Mockito.`when`(flashlightController.isAvailable).thenReturn(true) + Mockito.`when`(flashlightController.isEnabled).thenReturn(false) + val state = QSTile.BooleanState() + + tile.handleUpdateState(state, /* arg= */ null) + + Truth.assertThat(state.icon) + .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_flashlight_icon_off)) + } + + @Test + fun testIcon_whenFlashlightUnavailable_isOffState() { + Mockito.`when`(flashlightController.isAvailable).thenReturn(false) + val state = QSTile.BooleanState() + + tile.handleUpdateState(state, /* arg= */ null) + + Truth.assertThat(state.icon) + .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_flashlight_icon_off)) + } +} |