Merge "Adds the LightRevealScrim, and the 'lift' reveal effect."
This commit is contained in:
@@ -43,6 +43,12 @@
|
||||
android:visibility="invisible" />
|
||||
</com.android.systemui.statusbar.BackDropView>
|
||||
|
||||
<com.android.systemui.statusbar.LightRevealScrim
|
||||
android:id="@+id/light_reveal_scrim"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.android.systemui.statusbar.ScrimView
|
||||
android:id="@+id/scrim_behind"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
package com.android.systemui.statusbar
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PointF
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.PorterDuffXfermode
|
||||
import android.graphics.RadialGradient
|
||||
import android.graphics.Shader
|
||||
import android.os.SystemProperties
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import com.android.systemui.Interpolators
|
||||
|
||||
val enableLightReveal =
|
||||
SystemProperties.getBoolean("persist.sysui.show_new_screen_on_transitions", false)
|
||||
|
||||
/**
|
||||
* Provides methods to modify the various properties of a [LightRevealScrim] to reveal between 0% to
|
||||
* 100% of the view(s) underneath the scrim.
|
||||
*/
|
||||
interface LightRevealEffect {
|
||||
fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim)
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Returns the percent that the given value is past the threshold value. For example, 0.9 is
|
||||
* 50% of the way past 0.8.
|
||||
*/
|
||||
fun getPercentPastThreshold(value: Float, threshold: Float): Float {
|
||||
return (value - threshold).coerceAtLeast(0f) * (1f / (1f - threshold))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Light reveal effect that shows light entering the phone from the bottom of the screen. The light
|
||||
* enters from the bottom-middle as a narrow oval, and moves upward, eventually widening to fill the
|
||||
* screen.
|
||||
*/
|
||||
object LiftReveal : LightRevealEffect {
|
||||
|
||||
/** Widen the oval of light after 35%, so it will eventually fill the screen. */
|
||||
private const val WIDEN_OVAL_THRESHOLD = 0.35f
|
||||
|
||||
/** After 85%, fade out the black color at the end of the gradient. */
|
||||
private const val FADE_END_COLOR_OUT_THRESHOLD = 0.85f
|
||||
|
||||
/** The initial width of the light oval, in percent of scrim width. */
|
||||
private const val OVAL_INITIAL_WIDTH_PERCENT = 0.5f
|
||||
|
||||
/** The initial top value of the light oval, in percent of scrim height. */
|
||||
private const val OVAL_INITIAL_TOP_PERCENT = 1.05f
|
||||
|
||||
/** The initial bottom value of the light oval, in percent of scrim height. */
|
||||
private const val OVAL_INITIAL_BOTTOM_PERCENT = 1.2f
|
||||
|
||||
/** Interpolator to use for the reveal amount. */
|
||||
private val INTERPOLATOR = Interpolators.FAST_OUT_SLOW_IN_REVERSE
|
||||
|
||||
override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
|
||||
val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
|
||||
val ovalWidthIncreaseAmount =
|
||||
LightRevealEffect.getPercentPastThreshold(interpolatedAmount, WIDEN_OVAL_THRESHOLD)
|
||||
|
||||
val initialWidthMultiplier = (1f - OVAL_INITIAL_WIDTH_PERCENT) / 2f
|
||||
|
||||
with(scrim) {
|
||||
revealGradientEndColorAlpha = 1f - LightRevealEffect.getPercentPastThreshold(
|
||||
amount, FADE_END_COLOR_OUT_THRESHOLD)
|
||||
setRevealGradientBounds(
|
||||
scrim.width * initialWidthMultiplier +
|
||||
-scrim.width * ovalWidthIncreaseAmount,
|
||||
scrim.height * OVAL_INITIAL_TOP_PERCENT -
|
||||
scrim.height * interpolatedAmount,
|
||||
scrim.width * (1f - initialWidthMultiplier) +
|
||||
scrim.width * ovalWidthIncreaseAmount,
|
||||
scrim.height * OVAL_INITIAL_BOTTOM_PERCENT +
|
||||
scrim.height * interpolatedAmount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrim view that partially reveals the content underneath it using a [RadialGradient] with a
|
||||
* transparent center. The center position, size, and stops of the gradient can be manipulated to
|
||||
* reveal views below the scrim as if they are being 'lit up'.
|
||||
*/
|
||||
class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
|
||||
|
||||
/**
|
||||
* How much of the underlying views are revealed, in percent. 0 means they will be completely
|
||||
* obscured and 1 means they'll be fully visible.
|
||||
*/
|
||||
var revealAmount: Float = 0f
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
|
||||
revealEffect.setRevealAmountOnScrim(value, this)
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The [LightRevealEffect] used to manipulate the radial gradient whenever [revealAmount]
|
||||
* changes.
|
||||
*/
|
||||
var revealEffect: LightRevealEffect = LiftReveal
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
|
||||
revealEffect.setRevealAmountOnScrim(revealAmount, this)
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
var revealGradientCenter = PointF()
|
||||
var revealGradientWidth: Float = 0f
|
||||
var revealGradientHeight: Float = 0f
|
||||
|
||||
var revealGradientEndColor: Int = Color.BLACK
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
setPaintColorFilter()
|
||||
}
|
||||
}
|
||||
|
||||
var revealGradientEndColorAlpha = 0f
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
setPaintColorFilter()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint used to draw a transparent-to-white radial gradient. This will be scaled and translated
|
||||
* via local matrix in [onDraw] so we never need to construct a new shader.
|
||||
*/
|
||||
private val gradientPaint = Paint().apply {
|
||||
shader = RadialGradient(
|
||||
0f, 0f, 1f,
|
||||
intArrayOf(Color.TRANSPARENT, Color.WHITE), floatArrayOf(0f, 1f),
|
||||
Shader.TileMode.CLAMP)
|
||||
|
||||
// SRC_OVER ensures that we draw the semitransparent pixels over other views in the same
|
||||
// window, rather than outright replacing them.
|
||||
xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix applied to [gradientPaint]'s RadialGradient shader to move the gradient to
|
||||
* [revealGradientCenter] and set its size to [revealGradientWidth]/[revealGradientHeight],
|
||||
* without needing to construct a new shader each time those properties change.
|
||||
*/
|
||||
private val shaderGradientMatrix = Matrix()
|
||||
|
||||
/**
|
||||
* Sets bounds for the transparent oval gradient that reveals the views below the scrim. This is
|
||||
* simply a helper method that sets [revealGradientCenter], [revealGradientWidth], and
|
||||
* [revealGradientHeight] for you.
|
||||
*
|
||||
* This method does not call [invalidate] - you should do so once you're done changing
|
||||
* properties.
|
||||
*/
|
||||
public fun setRevealGradientBounds(left: Float, top: Float, right: Float, bottom: Float) {
|
||||
revealGradientWidth = right - left
|
||||
revealGradientHeight = bottom - top
|
||||
|
||||
revealGradientCenter.x = left + (revealGradientWidth / 2f)
|
||||
revealGradientCenter.y = top + (revealGradientHeight / 2f)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
if (canvas == null || revealGradientWidth <= 0 || revealGradientHeight <= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
with(shaderGradientMatrix) {
|
||||
setScale(revealGradientWidth, revealGradientHeight, 0f, 0f)
|
||||
postTranslate(revealGradientCenter.x, revealGradientCenter.y)
|
||||
|
||||
gradientPaint.shader.setLocalMatrix(this)
|
||||
}
|
||||
|
||||
// Draw the gradient over the screen, then multiply the end color by it.
|
||||
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), gradientPaint)
|
||||
}
|
||||
|
||||
private fun setPaintColorFilter() {
|
||||
gradientPaint.colorFilter = PorterDuffColorFilter(
|
||||
Color.argb(
|
||||
(revealGradientEndColorAlpha * 255).toInt(),
|
||||
Color.red(revealGradientEndColor),
|
||||
Color.green(revealGradientEndColor),
|
||||
Color.blue(revealGradientEndColor)),
|
||||
PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASL
|
||||
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
|
||||
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
|
||||
import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
|
||||
import static com.android.systemui.statusbar.LightRevealScrimKt.getEnableLightReveal;
|
||||
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
|
||||
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
|
||||
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
|
||||
@@ -181,6 +182,8 @@ import com.android.systemui.statusbar.CrossFadeHelper;
|
||||
import com.android.systemui.statusbar.GestureRecorder;
|
||||
import com.android.systemui.statusbar.KeyboardShortcuts;
|
||||
import com.android.systemui.statusbar.KeyguardIndicationController;
|
||||
import com.android.systemui.statusbar.LiftReveal;
|
||||
import com.android.systemui.statusbar.LightRevealScrim;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationMediaManager;
|
||||
import com.android.systemui.statusbar.NotificationPresenter;
|
||||
@@ -367,6 +370,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
DozeServiceHost mDozeServiceHost;
|
||||
private boolean mWakeUpComingFromTouch;
|
||||
private PointF mWakeUpTouchLocation;
|
||||
private LightRevealScrim mLightRevealScrim;
|
||||
|
||||
private final Object mQueueLock = new Object();
|
||||
|
||||
@@ -1155,6 +1159,13 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
});
|
||||
mScrimController.attachViews(scrimBehind, scrimInFront, scrimForBubble);
|
||||
|
||||
mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
|
||||
|
||||
if (getEnableLightReveal()) {
|
||||
mLightRevealScrim.setVisibility(View.VISIBLE);
|
||||
mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
|
||||
}
|
||||
|
||||
mNotificationPanelViewController.initDependencies(
|
||||
this,
|
||||
mNotificationShelfController);
|
||||
@@ -3618,6 +3629,13 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
Trace.endSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDozeAmountChanged(float linear, float eased) {
|
||||
if (getEnableLightReveal()) {
|
||||
mLightRevealScrim.setRevealAmount(1f - linear);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDozingChanged(boolean isDozing) {
|
||||
Trace.beginSection("StatusBar#updateDozing");
|
||||
|
||||
Reference in New Issue
Block a user