Merge "Animate power menu dialog from power button"
This commit is contained in:
committed by
Android (Google) Code Review
commit
1b23d0847e
@@ -22,7 +22,7 @@
|
||||
android:interpolator="@interpolator/standard"
|
||||
android:duration="@android:integer/config_activityDefaultDur" />
|
||||
<translate
|
||||
android:fromYDelta="20dp"
|
||||
android:fromYDelta="@android:dimen/popup_enter_animation_from_y_delta"
|
||||
android:toYDelta="0"
|
||||
android:interpolator="@interpolator/standard"
|
||||
android:duration="@android:integer/config_activityDefaultDur" />
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
android:duration="@android:integer/config_activityShortDur" />
|
||||
<translate
|
||||
android:fromYDelta="0"
|
||||
android:toYDelta="-10dp"
|
||||
android:toYDelta="@android:dimen/popup_exit_animation_to_y_delta"
|
||||
android:interpolator="@interpolator/standard_accelerate"
|
||||
android:duration="@android:integer/config_activityShortDur" />
|
||||
</set>
|
||||
|
||||
@@ -994,4 +994,8 @@
|
||||
|
||||
<!-- Default size for user icons (a.k.a. avatar images) -->
|
||||
<dimen name="user_icon_size">190dp</dimen>
|
||||
|
||||
<!-- Dimensions for the translations of the default dialog animation. -->
|
||||
<dimen name="popup_enter_animation_from_y_delta">20dp</dimen>
|
||||
<dimen name="popup_exit_animation_to_y_delta">-10dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -2358,6 +2358,10 @@
|
||||
<java-symbol type="string" name="nas_upgrade_notification_learn_more_action" />
|
||||
<java-symbol type="string" name="nas_upgrade_notification_learn_more_content" />
|
||||
<java-symbol type="bool" name="config_settingsHelpLinksEnabled" />
|
||||
<java-symbol type="integer" name="config_activityDefaultDur" />
|
||||
<java-symbol type="integer" name="config_activityShortDur" />
|
||||
<java-symbol type="dimen" name="popup_enter_animation_from_y_delta" />
|
||||
<java-symbol type="dimen" name="popup_exit_animation_to_y_delta" />
|
||||
|
||||
<!-- ImfTest -->
|
||||
<java-symbol type="layout" name="auto_complete_list" />
|
||||
|
||||
@@ -399,6 +399,11 @@
|
||||
<!-- that would otherwise be intercepted by the Shade. -->
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
|
||||
<!-- Empty enter/exit animation, we will animate in-window. Note that the implementation -->
|
||||
<!-- of ActionsDialogLite relies on this to be null (resource=0) to detect when to run -->
|
||||
<!-- the in-window animation. -->
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="QSBorderlessButton">
|
||||
|
||||
@@ -31,6 +31,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_G
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Dialog;
|
||||
@@ -76,8 +77,10 @@ import android.view.GestureDetector;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
@@ -109,6 +112,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.MultiListLayout;
|
||||
import com.android.systemui.MultiListLayout.MultiListAdapter;
|
||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
||||
import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
@@ -2170,6 +2174,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
|
||||
private Optional<StatusBar> mStatusBarOptional;
|
||||
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
private float mWindowDimAmount;
|
||||
|
||||
protected ViewGroup mContainer;
|
||||
|
||||
@@ -2251,6 +2256,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
initializeLayout();
|
||||
mWindowDimAmount = getWindow().getAttributes().dimAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2459,6 +2465,96 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
|
||||
mNotificationShadeWindowController.setRequestTopUi(true, TAG);
|
||||
mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, true)
|
||||
.commitUpdate(mContext.getDisplayId());
|
||||
|
||||
// By default this dialog windowAnimationStyle is null, and therefore windowAnimations
|
||||
// should be equal to 0 which means we need to animate the dialog in-window. If it's not
|
||||
// equal to 0, it means it has been overridden to animate (e.g. by the
|
||||
// DialogLaunchAnimator) so we don't run the animation.
|
||||
boolean shouldAnimateInWindow = getWindow().getAttributes().windowAnimations == 0;
|
||||
if (shouldAnimateInWindow) {
|
||||
startAnimation(true /* isEnter */, null /* then */);
|
||||
|
||||
// Override the dialog dismiss so that we can animate in-window before dismissing
|
||||
// the dialog.
|
||||
setDismissOverride(() -> {
|
||||
startAnimation(false /* isEnter */, /* then */ () -> {
|
||||
setDismissOverride(null);
|
||||
|
||||
// Hide then dismiss to instantly dismiss.
|
||||
hide();
|
||||
dismiss();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Run either the enter or exit animation, then run {@code then}. */
|
||||
private void startAnimation(boolean isEnter, @Nullable Runnable then) {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
|
||||
|
||||
// Note: these specs should be the same as in popup_enter_material and
|
||||
// popup_exit_material.
|
||||
float translationPx;
|
||||
Resources resources = getContext().getResources();
|
||||
if (isEnter) {
|
||||
translationPx = resources.getDimension(R.dimen.popup_enter_animation_from_y_delta);
|
||||
animator.setInterpolator(Interpolators.STANDARD);
|
||||
animator.setDuration(resources.getInteger(R.integer.config_activityDefaultDur));
|
||||
} else {
|
||||
translationPx = resources.getDimension(R.dimen.popup_exit_animation_to_y_delta);
|
||||
animator.setInterpolator(Interpolators.STANDARD_ACCELERATE);
|
||||
animator.setDuration(resources.getInteger(R.integer.config_activityShortDur));
|
||||
}
|
||||
|
||||
Window window = getWindow();
|
||||
int rotation = window.getWindowManager().getDefaultDisplay().getRotation();
|
||||
|
||||
animator.addUpdateListener(valueAnimator -> {
|
||||
float progress = (float) valueAnimator.getAnimatedValue();
|
||||
|
||||
float alpha = isEnter ? progress : 1 - progress;
|
||||
mGlobalActionsLayout.setAlpha(alpha);
|
||||
window.setDimAmount(mWindowDimAmount * alpha);
|
||||
|
||||
// TODO(b/213872558): Support devices that don't have their power button on the
|
||||
// right.
|
||||
float translation =
|
||||
isEnter ? translationPx * (1 - progress) : translationPx * progress;
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_0:
|
||||
mGlobalActionsLayout.setTranslationX(translation);
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
mGlobalActionsLayout.setTranslationY(-translation);
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
mGlobalActionsLayout.setTranslationX(-translation);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
mGlobalActionsLayout.setTranslationY(translation);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
private int mPreviousLayerType;
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation, boolean isReverse) {
|
||||
mPreviousLayerType = mGlobalActionsLayout.getLayerType();
|
||||
mGlobalActionsLayout.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mGlobalActionsLayout.setLayerType(mPreviousLayerType, null);
|
||||
if (then != null) {
|
||||
then.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
animator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ import junit.framework.Assert.assertNotNull
|
||||
import junit.framework.Assert.assertNull
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@@ -145,7 +146,31 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
|
||||
assertNull(dialogLaunchAnimator.createActivityLaunchController(dialog.contentView))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDialogAnimationIsChangedByAnimator() {
|
||||
// Important: the power menu animation relies on this behavior to know when to animate (see
|
||||
// http://ag/16774605).
|
||||
val dialog = runOnMainThreadAndWaitForIdleSync { TestDialog(context) }
|
||||
dialog.window.setWindowAnimations(0)
|
||||
assertEquals(0, dialog.window.attributes.windowAnimations)
|
||||
|
||||
val touchSurface = createTouchSurface()
|
||||
runOnMainThreadAndWaitForIdleSync {
|
||||
dialogLaunchAnimator.showFromView(dialog, touchSurface)
|
||||
}
|
||||
assertNotEquals(0, dialog.window.attributes.windowAnimations)
|
||||
}
|
||||
|
||||
private fun createAndShowDialog(): TestDialog {
|
||||
val touchSurface = createTouchSurface()
|
||||
return runOnMainThreadAndWaitForIdleSync {
|
||||
val dialog = TestDialog(context)
|
||||
dialogLaunchAnimator.showFromView(dialog, touchSurface)
|
||||
dialog
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTouchSurface(): View {
|
||||
return runOnMainThreadAndWaitForIdleSync {
|
||||
val touchSurfaceRoot = LinearLayout(context)
|
||||
val touchSurface = View(context)
|
||||
@@ -156,9 +181,7 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
|
||||
ViewUtils.attachView(touchSurfaceRoot)
|
||||
attachedViews.add(touchSurfaceRoot)
|
||||
|
||||
val dialog = TestDialog(context)
|
||||
dialogLaunchAnimator.showFromView(dialog, touchSurface)
|
||||
dialog
|
||||
touchSurface
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user