Merge "Merge "Scroll NotificationStack in sync with IME when inline replying" into tm-qpr-dev am: e1766512a2" into tm-qpr-dev-plus-aosp
This commit is contained in:
committed by
Android (Google) Code Review
commit
17bbfeca8c
@@ -109,6 +109,10 @@ object Flags {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val NOTIFICATION_ANIMATE_BIG_PICTURE = unreleasedFlag(120, "notification_animate_big_picture")
|
val NOTIFICATION_ANIMATE_BIG_PICTURE = unreleasedFlag(120, "notification_animate_big_picture")
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val ANIMATED_NOTIFICATION_SHADE_INSETS =
|
||||||
|
unreleasedFlag(270682168, "animated_notification_shade_insets", teamfood = true)
|
||||||
|
|
||||||
// 200 - keyguard/lockscreen
|
// 200 - keyguard/lockscreen
|
||||||
// ** Flag retired **
|
// ** Flag retired **
|
||||||
// public static final BooleanFlag KEYGUARD_LAYOUT =
|
// public static final BooleanFlag KEYGUARD_LAYOUT =
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ import android.view.ViewGroup;
|
|||||||
import android.view.ViewOutlineProvider;
|
import android.view.ViewOutlineProvider;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
|
import android.view.WindowInsetsAnimation;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
@@ -199,6 +200,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
private final boolean mDebugRemoveAnimation;
|
private final boolean mDebugRemoveAnimation;
|
||||||
private final boolean mSimplifiedAppearFraction;
|
private final boolean mSimplifiedAppearFraction;
|
||||||
private final boolean mUseRoundnessSourceTypes;
|
private final boolean mUseRoundnessSourceTypes;
|
||||||
|
private boolean mAnimatedInsets;
|
||||||
|
|
||||||
private int mContentHeight;
|
private int mContentHeight;
|
||||||
private float mIntrinsicContentHeight;
|
private float mIntrinsicContentHeight;
|
||||||
@@ -207,7 +209,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
private int mTopPadding;
|
private int mTopPadding;
|
||||||
private boolean mAnimateNextTopPaddingChange;
|
private boolean mAnimateNextTopPaddingChange;
|
||||||
private int mBottomPadding;
|
private int mBottomPadding;
|
||||||
private int mBottomInset = 0;
|
@VisibleForTesting
|
||||||
|
int mBottomInset = 0;
|
||||||
private float mQsExpansionFraction;
|
private float mQsExpansionFraction;
|
||||||
private final int mSplitShadeMinContentHeight;
|
private final int mSplitShadeMinContentHeight;
|
||||||
|
|
||||||
@@ -388,9 +391,33 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private boolean mPulsing;
|
private boolean mPulsing;
|
||||||
private boolean mScrollable;
|
private boolean mScrollable;
|
||||||
private View mForcedScroll;
|
private View mForcedScroll;
|
||||||
|
private boolean mIsInsetAnimationRunning;
|
||||||
|
|
||||||
|
private final WindowInsetsAnimation.Callback mInsetsCallback =
|
||||||
|
new WindowInsetsAnimation.Callback(
|
||||||
|
WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepare(WindowInsetsAnimation animation) {
|
||||||
|
mIsInsetAnimationRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WindowInsets onProgress(WindowInsets windowInsets,
|
||||||
|
List<WindowInsetsAnimation> list) {
|
||||||
|
updateBottomInset(windowInsets);
|
||||||
|
return windowInsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnd(WindowInsetsAnimation animation) {
|
||||||
|
mIsInsetAnimationRunning = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see #setHideAmount(float, float)
|
* @see #setHideAmount(float, float)
|
||||||
@@ -584,6 +611,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
|
mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
|
||||||
mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
|
mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
|
||||||
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
|
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
|
||||||
|
setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS));
|
||||||
mSectionsManager = Dependency.get(NotificationSectionsManager.class);
|
mSectionsManager = Dependency.get(NotificationSectionsManager.class);
|
||||||
mScreenOffAnimationController =
|
mScreenOffAnimationController =
|
||||||
Dependency.get(ScreenOffAnimationController.class);
|
Dependency.get(ScreenOffAnimationController.class);
|
||||||
@@ -622,6 +650,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
mGroupMembershipManager = Dependency.get(GroupMembershipManager.class);
|
mGroupMembershipManager = Dependency.get(GroupMembershipManager.class);
|
||||||
mGroupExpansionManager = Dependency.get(GroupExpansionManager.class);
|
mGroupExpansionManager = Dependency.get(GroupExpansionManager.class);
|
||||||
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
|
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||||
|
if (mAnimatedInsets) {
|
||||||
|
setWindowInsetsAnimationCallback(mInsetsCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -689,6 +720,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
mHasFilteredOutSeenNotifications = hasFilteredOutSeenNotifications;
|
mHasFilteredOutSeenNotifications = hasFilteredOutSeenNotifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void setAnimatedInsetsEnabled(boolean enabled) {
|
||||||
|
mAnimatedInsets = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||||
public void updateFooter() {
|
public void updateFooter() {
|
||||||
@@ -1781,7 +1817,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mForcedScroll = v;
|
mForcedScroll = v;
|
||||||
scrollTo(v);
|
if (mAnimatedInsets) {
|
||||||
|
updateForcedScroll();
|
||||||
|
} else {
|
||||||
|
scrollTo(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||||
@@ -1813,26 +1853,46 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
+ ((!isExpanded() && isPinnedHeadsUp(v)) ? mHeadsUpInset : getTopPadding());
|
+ ((!isExpanded() && isPinnedHeadsUp(v)) ? mHeadsUpInset : getTopPadding());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateBottomInset(WindowInsets windowInsets) {
|
||||||
|
mBottomInset = windowInsets.getInsets(WindowInsets.Type.ime()).bottom;
|
||||||
|
|
||||||
|
if (mForcedScroll != null) {
|
||||||
|
updateForcedScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
int range = getScrollRange();
|
||||||
|
if (mOwnScrollY > range) {
|
||||||
|
setOwnScrollY(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
||||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||||
mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom;
|
if (!mAnimatedInsets) {
|
||||||
|
mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom;
|
||||||
|
}
|
||||||
mWaterfallTopInset = 0;
|
mWaterfallTopInset = 0;
|
||||||
final DisplayCutout cutout = insets.getDisplayCutout();
|
final DisplayCutout cutout = insets.getDisplayCutout();
|
||||||
if (cutout != null) {
|
if (cutout != null) {
|
||||||
mWaterfallTopInset = cutout.getWaterfallInsets().top;
|
mWaterfallTopInset = cutout.getWaterfallInsets().top;
|
||||||
}
|
}
|
||||||
|
if (mAnimatedInsets && !mIsInsetAnimationRunning) {
|
||||||
int range = getScrollRange();
|
// update bottom inset e.g. after rotation
|
||||||
if (mOwnScrollY > range) {
|
updateBottomInset(insets);
|
||||||
// HACK: We're repeatedly getting staggered insets here while the IME is
|
}
|
||||||
// animating away. To work around that we'll wait until things have settled.
|
if (!mAnimatedInsets) {
|
||||||
removeCallbacks(mReclamp);
|
int range = getScrollRange();
|
||||||
postDelayed(mReclamp, 50);
|
if (mOwnScrollY > range) {
|
||||||
} else if (mForcedScroll != null) {
|
// HACK: We're repeatedly getting staggered insets here while the IME is
|
||||||
// The scroll was requested before we got the actual inset - in case we need
|
// animating away. To work around that we'll wait until things have settled.
|
||||||
// to scroll up some more do so now.
|
removeCallbacks(mReclamp);
|
||||||
scrollTo(mForcedScroll);
|
postDelayed(mReclamp, 50);
|
||||||
|
} else if (mForcedScroll != null) {
|
||||||
|
// The scroll was requested before we got the actual inset - in case we need
|
||||||
|
// to scroll up some more do so now.
|
||||||
|
scrollTo(mForcedScroll);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return insets;
|
return insets;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.statusbar.notification.stack;
|
package com.android.systemui.statusbar.notification.stack;
|
||||||
|
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
|
import static android.view.WindowInsets.Type.ime;
|
||||||
|
|
||||||
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
|
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
|
||||||
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
|
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
|
||||||
@@ -46,6 +47,7 @@ import static org.mockito.Mockito.spy;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.graphics.Insets;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
@@ -54,6 +56,8 @@ import android.util.MathUtils;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowInsets;
|
||||||
|
import android.view.WindowInsetsAnimation;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.test.annotation.UiThreadTest;
|
import androidx.test.annotation.UiThreadTest;
|
||||||
@@ -91,6 +95,8 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.MockitoJUnit;
|
import org.mockito.junit.MockitoJUnit;
|
||||||
import org.mockito.junit.MockitoRule;
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link NotificationStackScrollLayout}.
|
* Tests for {@link NotificationStackScrollLayout}.
|
||||||
*/
|
*/
|
||||||
@@ -843,6 +849,19 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
|||||||
verify(mEmptyShadeView).setFooterText(not(0));
|
verify(mEmptyShadeView).setFooterText(not(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWindowInsetAnimationProgress_updatesBottomInset() {
|
||||||
|
int bottomImeInset = 100;
|
||||||
|
mStackScrollerInternal.setAnimatedInsetsEnabled(true);
|
||||||
|
WindowInsets windowInsets = new WindowInsets.Builder()
|
||||||
|
.setInsets(ime(), Insets.of(0, 0, 0, bottomImeInset)).build();
|
||||||
|
ArrayList<WindowInsetsAnimation> windowInsetsAnimations = new ArrayList<>();
|
||||||
|
mStackScrollerInternal
|
||||||
|
.dispatchWindowInsetsAnimationProgress(windowInsets, windowInsetsAnimations);
|
||||||
|
|
||||||
|
assertEquals(bottomImeInset, mStackScrollerInternal.mBottomInset);
|
||||||
|
}
|
||||||
|
|
||||||
private void setBarStateForTest(int state) {
|
private void setBarStateForTest(int state) {
|
||||||
// Can't inject this through the listener or we end up on the actual implementation
|
// Can't inject this through the listener or we end up on the actual implementation
|
||||||
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
|
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
|
||||||
|
|||||||
Reference in New Issue
Block a user