Merge "[Status Bar] Display notif icon area during HUN even in lights out mode." into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
0911171b9e
@@ -81,6 +81,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
|
||||
private final KeyguardBypassController mBypassController;
|
||||
private final StatusBarStateController mStatusBarStateController;
|
||||
private final PhoneStatusBarTransitions mPhoneStatusBarTransitions;
|
||||
private final CommandQueue mCommandQueue;
|
||||
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
|
||||
|
||||
@@ -109,6 +110,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
NotificationIconAreaController notificationIconAreaController,
|
||||
HeadsUpManagerPhone headsUpManager,
|
||||
StatusBarStateController stateController,
|
||||
PhoneStatusBarTransitions phoneStatusBarTransitions,
|
||||
KeyguardBypassController bypassController,
|
||||
NotificationWakeUpCoordinator wakeUpCoordinator,
|
||||
DarkIconDispatcher darkIconDispatcher,
|
||||
@@ -156,6 +158,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
});
|
||||
mBypassController = bypassController;
|
||||
mStatusBarStateController = stateController;
|
||||
mPhoneStatusBarTransitions = phoneStatusBarTransitions;
|
||||
mWakeUpCoordinator = wakeUpCoordinator;
|
||||
mCommandQueue = commandQueue;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
@@ -203,6 +206,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
@Override
|
||||
public void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) {
|
||||
updateHeadsUpAndPulsingRoundness(entry);
|
||||
mPhoneStatusBarTransitions.onHeadsUpStateChanged(isHeadsUp);
|
||||
}
|
||||
|
||||
private void updateTopEntry() {
|
||||
|
||||
@@ -31,6 +31,8 @@ public final class PhoneStatusBarTransitions extends BarTransitions {
|
||||
|
||||
private final float mIconAlphaWhenOpaque;
|
||||
|
||||
private boolean mIsHeadsUp;
|
||||
|
||||
private View mStartSide, mStatusIcons, mBattery;
|
||||
private Animator mCurrentAnimation;
|
||||
|
||||
@@ -52,15 +54,32 @@ public final class PhoneStatusBarTransitions extends BarTransitions {
|
||||
return ObjectAnimator.ofFloat(v, "alpha", v.getAlpha(), toAlpha);
|
||||
}
|
||||
|
||||
private float getNonBatteryClockAlphaFor(int mode) {
|
||||
return isLightsOut(mode) ? ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK
|
||||
: !isOpaque(mode) ? ICON_ALPHA_WHEN_NOT_OPAQUE
|
||||
: mIconAlphaWhenOpaque;
|
||||
private float getStatusIconsAlphaFor(int mode) {
|
||||
return getDefaultAlphaFor(mode);
|
||||
}
|
||||
|
||||
private float getStartSideAlphaFor(int mode) {
|
||||
// When there's a heads up notification, we need the start side icons to show regardless of
|
||||
// lights out mode.
|
||||
if (mIsHeadsUp) {
|
||||
return getIconAlphaBasedOnOpacity(mode);
|
||||
}
|
||||
return getDefaultAlphaFor(mode);
|
||||
}
|
||||
|
||||
private float getBatteryClockAlpha(int mode) {
|
||||
return isLightsOut(mode) ? ICON_ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK
|
||||
: getNonBatteryClockAlphaFor(mode);
|
||||
: getIconAlphaBasedOnOpacity(mode);
|
||||
}
|
||||
|
||||
private float getDefaultAlphaFor(int mode) {
|
||||
return isLightsOut(mode) ? ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK
|
||||
: getIconAlphaBasedOnOpacity(mode);
|
||||
}
|
||||
|
||||
private float getIconAlphaBasedOnOpacity(int mode) {
|
||||
return !isOpaque(mode) ? ICON_ALPHA_WHEN_NOT_OPAQUE
|
||||
: mIconAlphaWhenOpaque;
|
||||
}
|
||||
|
||||
private boolean isOpaque(int mode) {
|
||||
@@ -74,19 +93,28 @@ public final class PhoneStatusBarTransitions extends BarTransitions {
|
||||
applyMode(newMode, animate);
|
||||
}
|
||||
|
||||
/** Informs this controller that the heads up notification state has changed. */
|
||||
public void onHeadsUpStateChanged(boolean isHeadsUp) {
|
||||
mIsHeadsUp = isHeadsUp;
|
||||
// We want the icon to be fully visible when the HUN appears, so just immediately change the
|
||||
// icon visibility and don't animate.
|
||||
applyMode(getMode(), /* animate= */ false);
|
||||
}
|
||||
|
||||
private void applyMode(int mode, boolean animate) {
|
||||
if (mStartSide == null) return; // pre-init
|
||||
float newAlpha = getNonBatteryClockAlphaFor(mode);
|
||||
float newAlphaBC = getBatteryClockAlpha(mode);
|
||||
float newStartSideAlpha = getStartSideAlphaFor(mode);
|
||||
float newStatusIconsAlpha = getStatusIconsAlphaFor(mode);
|
||||
float newBatteryAlpha = getBatteryClockAlpha(mode);
|
||||
if (mCurrentAnimation != null) {
|
||||
mCurrentAnimation.cancel();
|
||||
}
|
||||
if (animate) {
|
||||
AnimatorSet anims = new AnimatorSet();
|
||||
anims.playTogether(
|
||||
animateTransitionTo(mStartSide, newAlpha),
|
||||
animateTransitionTo(mStatusIcons, newAlpha),
|
||||
animateTransitionTo(mBattery, newAlphaBC)
|
||||
animateTransitionTo(mStartSide, newStartSideAlpha),
|
||||
animateTransitionTo(mStatusIcons, newStatusIconsAlpha),
|
||||
animateTransitionTo(mBattery, newBatteryAlpha)
|
||||
);
|
||||
if (isLightsOut(mode)) {
|
||||
anims.setDuration(LIGHTS_OUT_DURATION);
|
||||
@@ -94,9 +122,9 @@ public final class PhoneStatusBarTransitions extends BarTransitions {
|
||||
anims.start();
|
||||
mCurrentAnimation = anims;
|
||||
} else {
|
||||
mStartSide.setAlpha(newAlpha);
|
||||
mStatusIcons.setAlpha(newAlpha);
|
||||
mBattery.setAlpha(newAlphaBC);
|
||||
mStartSide.setAlpha(newStartSideAlpha);
|
||||
mStatusIcons.setAlpha(newStatusIconsAlpha);
|
||||
mBattery.setAlpha(newBatteryAlpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
private HeadsUpManagerPhone mHeadsUpManager;
|
||||
private View mOperatorNameView;
|
||||
private StatusBarStateController mStatusbarStateController;
|
||||
private PhoneStatusBarTransitions mPhoneStatusBarTransitions;
|
||||
private KeyguardBypassController mBypassController;
|
||||
private NotificationWakeUpCoordinator mWakeUpCoordinator;
|
||||
private KeyguardStateController mKeyguardStateController;
|
||||
@@ -95,6 +96,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
mHeadsUpManager = mock(HeadsUpManagerPhone.class);
|
||||
mOperatorNameView = new View(mContext);
|
||||
mStatusbarStateController = mock(StatusBarStateController.class);
|
||||
mPhoneStatusBarTransitions = mock(PhoneStatusBarTransitions.class);
|
||||
mBypassController = mock(KeyguardBypassController.class);
|
||||
mWakeUpCoordinator = mock(NotificationWakeUpCoordinator.class);
|
||||
mKeyguardStateController = mock(KeyguardStateController.class);
|
||||
@@ -105,6 +107,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
mock(NotificationIconAreaController.class),
|
||||
mHeadsUpManager,
|
||||
mStatusbarStateController,
|
||||
mPhoneStatusBarTransitions,
|
||||
mBypassController,
|
||||
mWakeUpCoordinator,
|
||||
mDarkIconDispatcher,
|
||||
@@ -188,6 +191,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
mock(NotificationIconAreaController.class),
|
||||
mHeadsUpManager,
|
||||
mStatusbarStateController,
|
||||
mPhoneStatusBarTransitions,
|
||||
mBypassController,
|
||||
mWakeUpCoordinator,
|
||||
mDarkIconDispatcher,
|
||||
@@ -283,4 +287,18 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
/* delta = */ 0.001
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onHeadsUpStateChanged_true_transitionsNotified() {
|
||||
mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, true);
|
||||
|
||||
verify(mPhoneStatusBarTransitions).onHeadsUpStateChanged(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onHeadsUpStateChanged_false_transitionsNotified() {
|
||||
mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, false);
|
||||
|
||||
verify(mPhoneStatusBarTransitions).onHeadsUpStateChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.statusbar.phone
|
||||
|
||||
import android.testing.TestableLooper
|
||||
import android.view.View
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT
|
||||
import com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT
|
||||
import com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE
|
||||
import com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT
|
||||
import com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT
|
||||
import com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.reset
|
||||
import org.mockito.Mockito.verify
|
||||
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
class PhoneStatusBarTransitionsTest : SysuiTestCase() {
|
||||
|
||||
// PhoneStatusBarView does a lot of non-standard things when inflating, so just use mocks.
|
||||
private val batteryView = mock<View>()
|
||||
private val statusIcons = mock<View>()
|
||||
private val startIcons = mock<View>()
|
||||
private val statusBarView =
|
||||
mock<PhoneStatusBarView>().apply {
|
||||
whenever(this.context).thenReturn(mContext)
|
||||
whenever(this.findViewById<View>(R.id.battery)).thenReturn(batteryView)
|
||||
whenever(this.findViewById<View>(R.id.statusIcons)).thenReturn(statusIcons)
|
||||
whenever(this.findViewById<View>(R.id.status_bar_start_side_except_heads_up))
|
||||
.thenReturn(startIcons)
|
||||
}
|
||||
private val backgroundView = mock<View>().apply { whenever(this.context).thenReturn(mContext) }
|
||||
|
||||
private val underTest: PhoneStatusBarTransitions by lazy {
|
||||
PhoneStatusBarTransitions(statusBarView, backgroundView).also {
|
||||
// The views' alphas will be set when PhoneStatusBarTransitions is created and we want
|
||||
// to ignore those in the tests, so clear those verifications here.
|
||||
reset(batteryView)
|
||||
reset(statusIcons)
|
||||
reset(startIcons)
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context.orCreateTestableResources.addOverride(
|
||||
R.dimen.status_bar_icon_drawing_alpha,
|
||||
RESOURCE_ALPHA,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_lightsOutMode_batteryTranslucent() {
|
||||
underTest.transitionTo(/* mode= */ MODE_LIGHTS_OUT, /* animate= */ false)
|
||||
|
||||
val alpha = batteryView.capturedAlpha()
|
||||
assertThat(alpha).isGreaterThan(0)
|
||||
assertThat(alpha).isLessThan(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_lightsOutMode_statusIconsHidden() {
|
||||
underTest.transitionTo(/* mode= */ MODE_LIGHTS_OUT, /* animate= */ false)
|
||||
|
||||
assertThat(statusIcons.capturedAlpha()).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_lightsOutMode_startIconsHidden() {
|
||||
underTest.transitionTo(/* mode= */ MODE_LIGHTS_OUT, /* animate= */ false)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_lightsOutTransparentMode_batteryTranslucent() {
|
||||
underTest.transitionTo(/* mode= */ MODE_LIGHTS_OUT_TRANSPARENT, /* animate= */ false)
|
||||
|
||||
val alpha = batteryView.capturedAlpha()
|
||||
assertThat(alpha).isGreaterThan(0)
|
||||
assertThat(alpha).isLessThan(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_lightsOutTransparentMode_statusIconsHidden() {
|
||||
underTest.transitionTo(/* mode= */ MODE_LIGHTS_OUT_TRANSPARENT, /* animate= */ false)
|
||||
|
||||
assertThat(statusIcons.capturedAlpha()).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_lightsOutTransparentMode_startIconsHidden() {
|
||||
underTest.transitionTo(/* mode= */ MODE_LIGHTS_OUT_TRANSPARENT, /* animate= */ false)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_translucentMode_batteryIconShown() {
|
||||
underTest.transitionTo(/* mode= */ MODE_TRANSLUCENT, /* animate= */ false)
|
||||
|
||||
assertThat(batteryView.capturedAlpha()).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_semiTransparentMode_statusIconsShown() {
|
||||
underTest.transitionTo(/* mode= */ MODE_SEMI_TRANSPARENT, /* animate= */ false)
|
||||
|
||||
assertThat(statusIcons.capturedAlpha()).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_transparentMode_startIconsShown() {
|
||||
// Transparent is the default, so we need to switch to a different mode first
|
||||
underTest.transitionTo(/* mode= */ MODE_OPAQUE, /* animate= */ false)
|
||||
reset(startIcons)
|
||||
|
||||
underTest.transitionTo(/* mode= */ MODE_TRANSPARENT, /* animate= */ false)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_opaqueMode_batteryIconUsesResourceAlpha() {
|
||||
underTest.transitionTo(/* mode= */ MODE_OPAQUE, /* animate= */ false)
|
||||
|
||||
assertThat(batteryView.capturedAlpha()).isEqualTo(RESOURCE_ALPHA)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_opaqueMode_statusIconsUseResourceAlpha() {
|
||||
underTest.transitionTo(/* mode= */ MODE_OPAQUE, /* animate= */ false)
|
||||
|
||||
assertThat(statusIcons.capturedAlpha()).isEqualTo(RESOURCE_ALPHA)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionTo_opaqueMode_startIconsUseResourceAlpha() {
|
||||
underTest.transitionTo(/* mode= */ MODE_OPAQUE, /* animate= */ false)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(RESOURCE_ALPHA)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onHeadsUpStateChanged_true_semiTransparentMode_startIconsShown() {
|
||||
underTest.transitionTo(/* mode= */ MODE_SEMI_TRANSPARENT, /* animate= */ false)
|
||||
reset(startIcons)
|
||||
|
||||
underTest.onHeadsUpStateChanged(true)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onHeadsUpStateChanged_true_opaqueMode_startIconsUseResourceAlpha() {
|
||||
underTest.transitionTo(/* mode= */ MODE_OPAQUE, /* animate= */ false)
|
||||
reset(startIcons)
|
||||
|
||||
underTest.onHeadsUpStateChanged(true)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(RESOURCE_ALPHA)
|
||||
}
|
||||
|
||||
/** Regression test for b/291173113. */
|
||||
@Test
|
||||
fun onHeadsUpStateChanged_true_lightsOutMode_startIconsUseResourceAlpha() {
|
||||
underTest.transitionTo(/* mode= */ MODE_LIGHTS_OUT, /* animate= */ false)
|
||||
reset(startIcons)
|
||||
|
||||
underTest.onHeadsUpStateChanged(true)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(RESOURCE_ALPHA)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onHeadsUpStateChanged_false_semiTransparentMode_startIconsShown() {
|
||||
underTest.transitionTo(/* mode= */ MODE_SEMI_TRANSPARENT, /* animate= */ false)
|
||||
reset(startIcons)
|
||||
|
||||
underTest.onHeadsUpStateChanged(false)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onHeadsUpStateChanged_false_opaqueMode_startIconsUseResourceAlpha() {
|
||||
underTest.transitionTo(/* mode= */ MODE_OPAQUE, /* animate= */ false)
|
||||
reset(startIcons)
|
||||
|
||||
underTest.onHeadsUpStateChanged(false)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(RESOURCE_ALPHA)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onHeadsUpStateChanged_false_lightsOutMode_startIconsHidden() {
|
||||
underTest.transitionTo(/* mode= */ MODE_LIGHTS_OUT, /* animate= */ false)
|
||||
reset(startIcons)
|
||||
|
||||
underTest.onHeadsUpStateChanged(false)
|
||||
|
||||
assertThat(startIcons.capturedAlpha()).isEqualTo(0)
|
||||
}
|
||||
|
||||
private fun View.capturedAlpha(): Float {
|
||||
val captor = argumentCaptor<Float>()
|
||||
verify(this).alpha = captor.capture()
|
||||
return captor.value
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val RESOURCE_ALPHA = 0.34f
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user