summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Selim Cinek <cinek@google.com> 2018-01-25 16:05:15 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-01-25 16:05:15 +0000
commitd41477f494ab03e5f8837effd681a77ad9a2c5db (patch)
treed34777c73cc5d5d67e1a7d607f545af1e76a571b
parent8e725bbad2780e74c7c974f9513efb71c6ecbab4 (diff)
parentde4de0e204a028f8f8608d7fd649fe1a60784c4e (diff)
Merge changes from topic "notification_launch"
* changes: Added the reply draft as an extra to the content intent Launching notification settings correctly inline Launching Notification animations inline
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/ContextImpl.java4
-rw-r--r--core/java/android/app/Instrumentation.java11
-rw-r--r--core/java/android/app/Notification.java10
-rw-r--r--core/java/android/app/TaskStackBuilder.java4
-rw-r--r--core/java/android/content/Context.java7
-rw-r--r--core/java/android/content/ContextWrapper.java4
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java11
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java107
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java242
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java121
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java23
29 files changed, 710 insertions, 74 deletions
diff --git a/api/current.txt b/api/current.txt
index d10f0784c0e3..a9bc98054903 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5227,6 +5227,7 @@ package android.app {
field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final java.lang.String EXTRA_REMOTE_INPUT_DRAFT = "android.remoteInputDraft";
field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
field public static final deprecated java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4914ffaf8912..ea940426f5a5 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -913,14 +913,14 @@ class ContextImpl extends Context {
/** @hide */
@Override
- public void startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
+ public int startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
if ((intents[0].getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivities() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag on first Intent."
+ " Is this really what you want?");
}
- mMainThread.getInstrumentation().execStartActivitiesAsUser(
+ return mMainThread.getInstrumentation().execStartActivitiesAsUser(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intents, options, userHandle.getIdentifier());
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 3c38a4ec5fe4..f90b276ac17f 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1688,9 +1688,13 @@ public class Instrumentation {
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
*
+ * @return The corresponding flag {@link ActivityManager#START_CANCELED},
+ * {@link ActivityManager#START_SUCCESS} etc. indicating whether the launch was
+ * successful.
+ *
* {@hide}
*/
- public void execStartActivitiesAsUser(Context who, IBinder contextThread,
+ public int execStartActivitiesAsUser(Context who, IBinder contextThread,
IBinder token, Activity target, Intent[] intents, Bundle options,
int userId) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
@@ -1705,11 +1709,11 @@ public class Instrumentation {
}
if (result != null) {
am.mHits++;
- return;
+ return ActivityManager.START_CANCELED;
} else if (am.match(who, null, intents[0])) {
am.mHits++;
if (am.isBlocking()) {
- return;
+ return ActivityManager.START_CANCELED;
}
break;
}
@@ -1727,6 +1731,7 @@ public class Instrumentation {
.startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,
token, options, userId);
checkStartActivityResult(result, intents[0]);
+ return result;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d6fddfca986e..0b5b363ddecd 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -200,6 +200,16 @@ public class Notification implements Parcelable
*/
private static final int MAX_REPLY_HISTORY = 5;
+
+ /**
+ * If the notification contained an unsent draft for a RemoteInput when the user clicked on it,
+ * we're adding the draft as a String extra to the {@link #contentIntent} using this key.
+ *
+ * <p>Apps may use this extra to prepopulate text fields in the app, where the user usually
+ * sends messages.</p>
+ */
+ public static final String EXTRA_REMOTE_INPUT_DRAFT = "android.remoteInputDraft";
+
/**
* A timestamp related to this notification, in milliseconds since the epoch.
*
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
index bab993f855e9..ab5974777c9e 100644
--- a/core/java/android/app/TaskStackBuilder.java
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -213,13 +213,13 @@ public class TaskStackBuilder {
* Start the task stack constructed by this builder.
* @hide
*/
- public void startActivities(Bundle options, UserHandle userHandle) {
+ public int startActivities(Bundle options, UserHandle userHandle) {
if (mIntents.isEmpty()) {
throw new IllegalStateException(
"No intents added to TaskStackBuilder; cannot startActivities");
}
- mSourceContext.startActivitiesAsUser(getIntents(), options, userHandle);
+ return mSourceContext.startActivitiesAsUser(getIntents(), options, userHandle);
}
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 1b050330ceb6..5177e102425a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -32,6 +32,7 @@ import android.annotation.StyleableRes;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.VrManager;
@@ -1834,13 +1835,17 @@ public abstract class Context {
* See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*
+ * @return The corresponding flag {@link ActivityManager#START_CANCELED},
+ * {@link ActivityManager#START_SUCCESS} etc. indicating whether the launch was
+ * successful.
+ *
* @throws ActivityNotFoundException &nbsp;
*
* @see #startActivities(Intent[])
* @see PackageManager#resolveActivity
*/
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- public void startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
+ public int startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 67de4fe6bc4b..8c1293e5b298 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -418,8 +418,8 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
- public void startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
- mBase.startActivitiesAsUser(intents, options, userHandle);
+ public int startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
+ return mBase.startActivitiesAsUser(intents, options, userHandle);
}
@Override
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0949a90877e1..6c8aaf0b1e8c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -350,6 +350,7 @@ applications that come with the platform
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
<permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
<permission name="android.permission.CONTROL_VPN"/>
<permission name="android.permission.DUMP"/>
<permission name="android.permission.GET_APP_OPS_STATS"/>
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 6c3aea2202a2..f5a6f4910b1b 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -42,6 +42,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
+import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -814,6 +815,16 @@ public class GradientDrawable extends Drawable {
}
}
+ /**
+ * @param mode to draw this drawable with
+ * @hide
+ */
+ @Override
+ public void setXfermode(@Nullable Xfermode mode) {
+ super.setXfermode(mode);
+ mFillPaint.setXfermode(mode);
+ }
+
private void buildPathIfDirty() {
final GradientState st = mGradientState;
if (mPathIsDirty) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 42b7213e84f0..1fc36bef215d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -200,6 +200,9 @@
<!-- to access instant apps -->
<uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" />
+ <!-- to control remote app transitions -->
+ <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
+
<!-- to change themes - light or dark -->
<uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index e59c703afdd8..eb5619b11487 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -122,7 +122,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private Interpolator mCurrentAppearInterpolator;
private Interpolator mCurrentAlphaInterpolator;
- private NotificationBackgroundView mBackgroundNormal;
+ protected NotificationBackgroundView mBackgroundNormal;
private NotificationBackgroundView mBackgroundDimmed;
private ObjectAnimator mBackgroundAnimator;
private RectF mAppearAnimationRect = new RectF();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 5112d37c830c..1056ecc9bf6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
import android.animation.Animator;
@@ -37,6 +38,7 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.MathUtils;
import android.util.Property;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -67,6 +69,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.statusbar.NotificationGuts.GutsContent;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -75,6 +78,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.stack.AmbientState;
import com.android.systemui.statusbar.stack.AnimationProperties;
import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
@@ -113,6 +117,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private int mNotificationMaxHeight;
private int mNotificationAmbientHeight;
private int mIncreasedPaddingBetweenElements;
+ private int mNotificationLaunchHeight;
private boolean mMustStayOnScreen;
/** Does this row contain layouts that can adapt to row expansion */
@@ -172,6 +177,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mIsSystemChildExpanded;
private boolean mIsPinned;
private FalsingManager mFalsingManager;
+ private boolean mExpandAnimationRunning;
private AboveShelfChangedListener mAboveShelfChangedListener;
private HeadsUpManager mHeadsUpManager;
private View mHelperButton;
@@ -270,6 +276,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private float mTranslationWhenRemoved;
private boolean mWasChildInGroupWhenRemoved;
private int mNotificationColorAmbient;
+ private NotificationViewState mNotificationViewState;
@Override
public boolean isGroupExpansionChanging() {
@@ -363,6 +370,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mNotificationInflater.inflateNotificationViews();
}
+ @Override
+ public void setPressed(boolean pressed) {
+ if (isOnKeyguard() || mEntry.notification.getNotification().contentIntent == null) {
+ // We're dropping the ripple if we have a collapse / launch animation
+ super.setPressed(pressed);
+ }
+ }
+
public void onNotificationUpdated() {
for (NotificationContentView l : mLayouts) {
l.onNotificationUpdated(mEntry);
@@ -1169,6 +1184,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private void updateContentTransformation() {
+ if (mExpandAnimationRunning) {
+ return;
+ }
float contentAlpha;
float translationY = -mContentTransformationAmount * mIconTransformContentShift;
if (mIsLastChild) {
@@ -1450,6 +1468,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mMenuRow.resetMenu();
}
+ public CharSequence getActiveRemoteInputText() {
+ return mPrivateLayout.getActiveRemoteInputText();
+ }
+
+
public void animateTranslateNotification(final float leftTarget) {
if (mTranslateAnim != null) {
mTranslateAnim.cancel();
@@ -1537,10 +1560,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private void updateChildrenVisibility() {
- mPrivateLayout.setVisibility(!shouldShowPublic() && !mIsSummaryWithChildren ? VISIBLE
- : INVISIBLE);
+ boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
+ && mGuts.isExposed();
+ mPrivateLayout.setVisibility(!shouldShowPublic() && !mIsSummaryWithChildren
+ && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
if (mChildrenContainer != null) {
- mChildrenContainer.setVisibility(!shouldShowPublic() && mIsSummaryWithChildren ? VISIBLE
+ mChildrenContainer.setVisibility(!shouldShowPublic() && mIsSummaryWithChildren
+ && !hideContentWhileLaunching ? VISIBLE
: INVISIBLE);
}
// The limits might have changed if the view suddenly became a group or vice versa
@@ -1579,6 +1605,62 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
updateShelfIconColor();
}
+ public void applyExpandAnimationParams(ExpandAnimationParameters params) {
+ if (params == null) {
+ return;
+ }
+ setTranslationY(params.getTop());
+ float zProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ params.getProgress(0, 50));
+ float translationZ = MathUtils.lerp(params.getStartTranslationZ(),
+ mNotificationLaunchHeight,
+ zProgress);
+ setTranslationZ(translationZ);
+ setActualHeight(params.getHeight());
+ mBackgroundNormal.setExpandAnimationParams(params);
+ }
+
+ public void setExpandAnimationRunning(boolean expandAnimationRunning) {
+ if (expandAnimationRunning) {
+ View contentView;
+ if (mIsSummaryWithChildren) {
+ contentView = mChildrenContainer;
+ } else {
+ contentView = getShowingLayout();
+ }
+ if (mGuts != null && mGuts.isExposed()) {
+ contentView = mGuts;
+ }
+ contentView.animate()
+ .alpha(0f)
+ .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT)
+ .setInterpolator(Interpolators.ALPHA_OUT);
+ setAboveShelf(true);
+ mExpandAnimationRunning = true;
+ mNotificationViewState.cancelAnimations(this);
+ mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext());
+ } else {
+ mExpandAnimationRunning = false;
+ setAboveShelf(isAboveShelf());
+ if (mGuts != null) {
+ mGuts.setAlpha(1.0f);
+ }
+ }
+ updateChildrenVisibility();
+ updateClipping();
+ mBackgroundNormal.setExpandAnimationRunning(expandAnimationRunning);
+ }
+
+ @Override
+ protected boolean shouldClipToActualHeight() {
+ return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
+ }
+
+ @Override
+ public boolean isExpandAnimationRunning() {
+ return mExpandAnimationRunning;
+ }
+
/**
* Tap sounds should not be played when we're unlocking.
* Doing so would cause audio collision and the system would feel unpolished.
@@ -2152,6 +2234,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public void setClipBottomAmount(int clipBottomAmount) {
+ if (mExpandAnimationRunning) {
+ return;
+ }
if (clipBottomAmount != mClipBottomAmount) {
super.setClipBottomAmount(clipBottomAmount);
for (NotificationContentView l : mLayouts) {
@@ -2361,13 +2446,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
- return new NotificationViewState(stackScrollState);
+ mNotificationViewState = new NotificationViewState(stackScrollState);
+ return mNotificationViewState;
}
@Override
public boolean isAboveShelf() {
return !isOnKeyguard()
- && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf));
+ && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
+ || mExpandAnimationRunning);
}
public void setShowAmbient(boolean showAmbient) {
@@ -2453,9 +2540,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public void applyToView(View view) {
- super.applyToView(view);
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.isExpandAnimationRunning()) {
+ return;
+ }
+ super.applyToView(view);
row.applyChildrenState(mOverallState);
}
}
@@ -2473,9 +2563,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public void animateTo(View child, AnimationProperties properties) {
- super.animateTo(child, properties);
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (row.isExpandAnimationRunning()) {
+ return;
+ }
+ super.animateTo(child, properties);
row.startChildAnimation(mOverallState, properties);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index eafa825dd89d..1496a41a9b47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -151,6 +151,10 @@ public abstract class ExpandableView extends FrameLayout {
return mActualHeight;
}
+ public boolean isExpandAnimationRunning() {
+ return false;
+ }
+
/**
* @return The maximum height of this notification.
*/
@@ -375,8 +379,8 @@ public abstract class ExpandableView extends FrameLayout {
return false;
}
- private void updateClipping() {
- if (mClipToActualHeight) {
+ protected void updateClipping() {
+ if (mClipToActualHeight && shouldClipToActualHeight()) {
int top = getClipTopAmount();
mClipRect.set(0, top, getWidth(), Math.max(getActualHeight() + getExtraBottomPadding()
- mClipBottomAmount, top));
@@ -386,6 +390,10 @@ public abstract class ExpandableView extends FrameLayout {
}
}
+ protected boolean shouldClipToActualHeight() {
+ return true;
+ }
+
public void setClipToActualHeight(boolean clipToActualHeight) {
mClipToActualHeight = clipToActualHeight;
updateClipping();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 45b35d014e70..d6beb7fb2699 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
@@ -27,7 +28,9 @@ import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
/**
* A view that can be used for both the dimmed and normal background of an notification.
@@ -44,6 +47,9 @@ public class NotificationBackgroundView extends View {
private boolean mBottomIsRounded;
private int mBackgroundTop;
private boolean mBottomAmountClips = true;
+ private boolean mExpandAnimationRunning;
+ private float mActualWidth;
+ private int mDrawableAlpha = 255;
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -53,9 +59,12 @@ public class NotificationBackgroundView extends View {
@Override
protected void onDraw(Canvas canvas) {
- if (mClipTopAmount + mClipBottomAmount < mActualHeight - mBackgroundTop) {
+ if (mClipTopAmount + mClipBottomAmount < mActualHeight - mBackgroundTop
+ || mExpandAnimationRunning) {
canvas.save();
- canvas.clipRect(0, mClipTopAmount, getWidth(), mActualHeight - mClipBottomAmount);
+ if (!mExpandAnimationRunning) {
+ canvas.clipRect(0, mClipTopAmount, getWidth(), mActualHeight - mClipBottomAmount);
+ }
draw(canvas, mBackground);
canvas.restore();
}
@@ -64,10 +73,16 @@ public class NotificationBackgroundView extends View {
private void draw(Canvas canvas, Drawable drawable) {
if (drawable != null) {
int bottom = mActualHeight;
- if (mBottomIsRounded && mBottomAmountClips) {
+ if (mBottomIsRounded && mBottomAmountClips && !mExpandAnimationRunning) {
bottom -= mClipBottomAmount;
}
- drawable.setBounds(0, mBackgroundTop, getWidth(), bottom);
+ int left = 0;
+ int right = getWidth();
+ if (mExpandAnimationRunning) {
+ left = (int) ((getWidth() - mActualWidth) / 2.0f);
+ right = (int) (left + mActualWidth);
+ }
+ drawable.setBounds(left, mBackgroundTop, right, bottom);
drawable.draw(canvas);
}
}
@@ -133,6 +148,9 @@ public class NotificationBackgroundView extends View {
}
public void setActualHeight(int actualHeight) {
+ if (mExpandAnimationRunning) {
+ return;
+ }
mActualHeight = actualHeight;
invalidate();
}
@@ -170,6 +188,10 @@ public class NotificationBackgroundView extends View {
}
public void setDrawableAlpha(int drawableAlpha) {
+ mDrawableAlpha = drawableAlpha;
+ if (mExpandAnimationRunning) {
+ return;
+ }
mBackground.setAlpha(drawableAlpha);
}
@@ -208,4 +230,29 @@ public class NotificationBackgroundView extends View {
mBackgroundTop = backgroundTop;
invalidate();
}
+
+ public void setExpandAnimationParams(ActivityLaunchAnimator.ExpandAnimationParameters params) {
+ mActualHeight = params.getHeight();
+ mActualWidth = params.getWidth();
+ float alphaProgress = Interpolators.ALPHA_IN.getInterpolation(
+ params.getProgress(
+ ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT /* delay */,
+ ActivityLaunchAnimator.ANIMATION_DURATION_FADE_APP /* duration */));
+ mBackground.setAlpha((int) (mDrawableAlpha * (1.0f - alphaProgress)));
+ invalidate();
+ }
+
+ public void setExpandAnimationRunning(boolean running) {
+ mExpandAnimationRunning = running;
+ if (mBackground instanceof LayerDrawable) {
+ GradientDrawable gradientDrawable =
+ (GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0);
+ gradientDrawable.setXfermode(
+ running ? new PorterDuffXfermode(PorterDuff.Mode.SRC) : null);
+ }
+ if (!mExpandAnimationRunning) {
+ setDrawableAlpha(mDrawableAlpha);
+ }
+ invalidate();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index a4c17e3681b0..e811ed3d77ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -1563,4 +1563,14 @@ public class NotificationContentView extends FrameLayout {
}
return visibleWrapper.shouldClipToRounding(topRounded, bottomRounded);
}
+
+ public CharSequence getActiveRemoteInputText() {
+ if (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive()) {
+ return mExpandedRemoteInput.getText();
+ }
+ if (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive()) {
+ return mHeadsUpRemoteInput.getText();
+ }
+ return null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index 9d8892da3c74..b9e672515499 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -41,7 +41,6 @@ import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -133,14 +132,14 @@ public class NotificationGutsManager implements Dumpable {
* channel.
*/
private void startAppNotificationSettingsActivity(String packageName, final int appUid,
- final NotificationChannel channel) {
+ final NotificationChannel channel, ExpandableNotificationRow row) {
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
intent.putExtra(Settings.EXTRA_APP_UID, appUid);
if (channel != null) {
intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channel.getId());
}
- mPresenter.startNotificationGutsIntent(intent, appUid);
+ mPresenter.startNotificationGutsIntent(intent, appUid, row);
}
public void bindGuts(final ExpandableNotificationRow row) {
@@ -198,14 +197,14 @@ public class NotificationGutsManager implements Dumpable {
mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_INFO);
guts.resetFalsingCheck();
mOnSettingsClickListener.onClick(sbn.getKey());
- startAppNotificationSettingsActivity(pkg, appUid, channel);
+ startAppNotificationSettingsActivity(pkg, appUid, channel, row);
};
}
final NotificationInfo.OnAppSettingsClickListener onAppSettingsClick = (View v,
Intent intent) -> {
mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_APP_NOTE_SETTINGS);
guts.resetFalsingCheck();
- mPresenter.startNotificationGutsIntent(intent, sbn.getUid());
+ mPresenter.startNotificationGutsIntent(intent, sbn.getUid(), row);
};
final View.OnClickListener onDoneClick = (View v) -> {
saveAndCloseNotificationMenu(row, guts, v);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java
index 43be44deedc8..0c19ec091ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+
import android.view.View;
import android.view.ViewGroup;
@@ -179,4 +181,11 @@ public interface NotificationListContainer {
* @return true if has pulsing notifications
*/
boolean hasPulsingNotifications();
+
+ /**
+ * Apply parameters of the expand animation to the layout
+ */
+ default void applyExpandAnimationParams(ExpandAnimationParameters params) {}
+
+ default void setExpandingNotification(ExpandableNotificationRow row) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 12641a0eca8c..5263bb4173a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -16,9 +16,7 @@
package com.android.systemui.statusbar;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.Handler;
-import android.service.notification.StatusBarNotification;
import android.view.View;
/**
@@ -48,7 +46,7 @@ public interface NotificationPresenter extends NotificationData.Environment,
* Runs the given intent. The presenter may want to run some animations or close itself when
* this happens.
*/
- void startNotificationGutsIntent(Intent intent, int appUid);
+ void startNotificationGutsIntent(Intent intent, int appUid, ExpandableNotificationRow row);
/**
* Returns the Handler for NotificationPresenter.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
new file mode 100644
index 000000000000..8336d29f2870
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2018 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.notification;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.app.ActivityOptions;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.MathUtils;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationTarget;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.ViewRootImpl;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationListContainer;
+import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+
+import java.util.function.Consumer;
+
+/**
+ * A class that allows activities to be launched in a seamless way where the notification
+ * transforms nicely into the starting window.
+ */
+public class ActivityLaunchAnimator {
+
+ private static final int ANIMATION_DURATION = 400;
+ public static final long ANIMATION_DURATION_FADE_CONTENT = 67;
+ public static final long ANIMATION_DURATION_FADE_APP = 200;
+ public static final long ANIMATION_DELAY_ICON_FADE_IN = ANIMATION_DURATION -
+ CollapsedStatusBarFragment.FADE_IN_DURATION - CollapsedStatusBarFragment.FADE_IN_DELAY
+ - 16;
+ private final NotificationPanelView mNotificationPanel;
+ private final NotificationListContainer mNotificationContainer;
+ private final StatusBarWindowView mStatusBarWindow;
+ private final Consumer<Boolean> mPanelCollapser;
+
+ public ActivityLaunchAnimator(StatusBarWindowView statusBarWindow,
+ Consumer<Boolean> panelCollapser,
+ NotificationPanelView notificationPanel,
+ NotificationListContainer container) {
+ mNotificationPanel = notificationPanel;
+ mNotificationContainer = container;
+ mStatusBarWindow = statusBarWindow;
+ mPanelCollapser = panelCollapser;
+ }
+
+ public ActivityOptions getLaunchAnimation(
+ ExpandableNotificationRow sourceNofitication) {
+ AnimationRunner animationRunner = new AnimationRunner(sourceNofitication);
+ return ActivityOptions.makeRemoteAnimation(
+ new RemoteAnimationAdapter(animationRunner, 1000 /* Duration */, 0 /* delay */));
+ }
+
+ class AnimationRunner extends IRemoteAnimationRunner.Stub {
+
+ private final ExpandableNotificationRow mSourceNotification;
+ private final ExpandAnimationParameters mParams;
+ private final Rect mWindowCrop = new Rect();
+ private boolean mLeashShown;
+ private boolean mInstantCollapsePanel = true;
+
+ public AnimationRunner(ExpandableNotificationRow sourceNofitication) {
+ mSourceNotification = sourceNofitication;
+ mParams = new ExpandAnimationParameters();
+ }
+
+ @Override
+ public void onAnimationStart(RemoteAnimationTarget[] remoteAnimationTargets,
+ IRemoteAnimationFinishedCallback iRemoteAnimationFinishedCallback)
+ throws RemoteException {
+ mSourceNotification.post(() -> {
+ boolean first = true;
+ for (RemoteAnimationTarget app : remoteAnimationTargets) {
+ if (app.mode == RemoteAnimationTarget.MODE_OPENING) {
+ setExpandAnimationRunning(true);
+ mInstantCollapsePanel = app.position.y == 0
+ && app.sourceContainerBounds.height()
+ >= mNotificationPanel.getHeight();
+ if (!mInstantCollapsePanel) {
+ mNotificationPanel.collapseWithDuration(ANIMATION_DURATION);
+ }
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ mParams.startPosition = mSourceNotification.getLocationOnScreen();
+ mParams.startTranslationZ = mSourceNotification.getTranslationZ();
+ int targetWidth = app.sourceContainerBounds.width();
+ int notificationHeight = mSourceNotification.getActualHeight();
+ int notificationWidth = mSourceNotification.getWidth();
+ anim.setDuration(ANIMATION_DURATION);
+ anim.setInterpolator(Interpolators.LINEAR);
+ anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mParams.linearProgress = animation.getAnimatedFraction();
+ float progress
+ = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ mParams.linearProgress);
+ int newWidth = (int) MathUtils.lerp(notificationWidth,
+ targetWidth, progress);
+ mParams.left = (int) ((targetWidth - newWidth) / 2.0f);
+ mParams.right = mParams.left + newWidth;
+ mParams.top = (int) MathUtils.lerp(mParams.startPosition[1],
+ app.position.y, progress);
+ mParams.bottom = (int) MathUtils.lerp(mParams.startPosition[1]
+ + notificationHeight,
+ app.position.y + app.sourceContainerBounds.bottom,
+ progress);
+ applyParamsToWindow(app);
+ applyParamsToNotification(mParams);
+ applyParamsToNotificationList(mParams);
+ }
+ });
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setExpandAnimationRunning(false);
+ if (mInstantCollapsePanel) {
+ mPanelCollapser.accept(false /* animate */);
+ }
+ try {
+ iRemoteAnimationFinishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ anim.start();
+ break;
+ }
+ }
+ });
+ }
+
+ private void setExpandAnimationRunning(boolean running) {
+ mNotificationPanel.setLaunchingNotification(running);
+ mSourceNotification.setExpandAnimationRunning(running);
+ mStatusBarWindow.setExpandAnimationRunning(running);
+ mNotificationContainer.setExpandingNotification(running ? mSourceNotification : null);
+ if (!running) {
+ applyParamsToNotification(null);
+ applyParamsToNotificationList(null);
+ }
+
+ }
+
+ private void applyParamsToNotificationList(ExpandAnimationParameters params) {
+ mNotificationContainer.applyExpandAnimationParams(params);
+ mNotificationPanel.applyExpandAnimationParams(params);
+ }
+
+ private void applyParamsToNotification(ExpandAnimationParameters params) {
+ mSourceNotification.applyExpandAnimationParams(params);
+ }
+
+ private void applyParamsToWindow(RemoteAnimationTarget app) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ if (!mLeashShown) {
+ t.show(app.leash);
+ mLeashShown = true;
+ }
+ Matrix m = new Matrix();
+ m.postTranslate(0, (float) (mParams.top - app.position.y));
+ t.setMatrix(app.leash, m, new float[9]);
+ mWindowCrop.set(mParams.left, 0, mParams.right, mParams.getHeight());
+ t.setWindowCrop(app.leash, mWindowCrop);
+ ViewRootImpl viewRootImpl = mSourceNotification.getViewRootImpl();
+ if (viewRootImpl != null) {
+ Surface systemUiSurface = viewRootImpl.mSurface;
+ t.deferTransactionUntilSurface(app.leash, systemUiSurface,
+ systemUiSurface.getNextFrameNumber());
+ }
+ t.apply();
+ }
+
+ @Override
+ public void onAnimationCancelled() throws RemoteException {
+ }
+ };
+
+ public static class ExpandAnimationParameters {
+ float linearProgress;
+ int[] startPosition;
+ float startTranslationZ;
+ int left;
+ int top;
+ int right;
+ int bottom;
+
+ public ExpandAnimationParameters() {
+ }
+
+ public int getTop() {
+ return top;
+ }
+
+ public int getWidth() {
+ return right - left;
+ }
+
+ public int getHeight() {
+ return bottom - top;
+ }
+
+ public int getTopChange() {
+ return Math.min(top - startPosition[1], 0);
+ }
+
+
+ public float getProgress(long delay, long duration) {
+ return MathUtils.constrain((linearProgress * ANIMATION_DURATION - delay)
+ / duration, 0.0f, 1.0f);
+ }
+
+ public float getStartTranslationZ() {
+ return startTranslationZ;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 61cb61ce1df4..f7f791ebaf63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -51,6 +51,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
public static final String TAG = "CollapsedStatusBarFragment";
private static final String EXTRA_PANEL_STATE = "panel_state";
+ public static final int FADE_IN_DURATION = 320;
+ public static final int FADE_IN_DELAY = 50;
private PhoneStatusBarView mStatusBar;
private KeyguardMonitor mKeyguardMonitor;
private NetworkController mNetworkController;
@@ -257,9 +259,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
v.animate()
.alpha(1f)
- .setDuration(320)
+ .setDuration(FADE_IN_DURATION)
.setInterpolator(Interpolators.ALPHA_IN)
- .setStartDelay(50)
+ .setStartDelay(FADE_IN_DELAY)
// We need to clean up any pending end action from animateHide if we call
// both hide and show in the same frame before the animation actually gets started.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 66cb59e3d317..5d3cc34ca8b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -65,6 +67,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
@@ -241,6 +244,8 @@ public class NotificationPanelView extends PanelView implements
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private boolean mUserSetupComplete;
private int mQsNotificationTopPadding;
+ private float mExpandOffset;
+ private boolean mHideIconsDuringNotificationLaunch = true;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -1675,8 +1680,9 @@ public class NotificationPanelView extends PanelView implements
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
return 0;
}
- float translation = NotificationUtils.interpolate(-mQsMinExpansionHeight, 0,
- mNotificationStackScroller.getAppearFraction(mExpandedHeight));
+ float translation = MathUtils.lerp(-mQsMinExpansionHeight, 0,
+ Math.min(1.0f, mNotificationStackScroller.getAppearFraction(mExpandedHeight)))
+ + mExpandOffset;
return Math.min(0, translation);
}
@@ -2540,6 +2546,9 @@ public class NotificationPanelView extends PanelView implements
}
public boolean hideStatusBarIconsWhenExpanded() {
+ if (mLaunchingNotification) {
+ return mHideIconsDuringNotificationLaunch;
+ }
return !isFullWidth() || !mShowIconsWhenExpanded;
}
@@ -2665,4 +2674,19 @@ public class NotificationPanelView extends PanelView implements
public LockIcon getLockIcon() {
return mKeyguardBottomArea.getLockIcon();
}
+
+ public void applyExpandAnimationParams(ExpandAnimationParameters params) {
+ mExpandOffset = params != null ? params.getTopChange() : 0;
+ updateQsExpansion();
+ if (params != null) {
+ boolean hideIcons = params.getProgress(
+ ActivityLaunchAnimator.ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
+ if (hideIcons != mHideIconsDuringNotificationLaunch) {
+ mHideIconsDuringNotificationLaunch = hideIcons;
+ if (!hideIcons) {
+ mStatusBar.recomputeDisableFlags(true /* animate */);
+ }
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2fc22caa6c05..a62a424caaf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -60,12 +60,15 @@ public abstract class PanelView extends FrameLayout {
public static final String TAG = PanelView.class.getSimpleName();
private static final int INITIAL_OPENING_PEEK_DURATION = 200;
private static final int PEEK_ANIMATION_DURATION = 360;
+ private static final int NO_FIXED_DURATION = -1;
private long mDownTime;
private float mMinExpandHeight;
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mPanelUpdateWhenAnimatorEnds;
private boolean mVibrateOnOpening;
private boolean mVibrationEnabled;
+ protected boolean mLaunchingNotification;
+ private int mFixedDuration = NO_FIXED_DURATION;
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -785,6 +788,9 @@ public abstract class PanelView extends FrameLayout {
if (vel == 0) {
animator.setDuration((long) (animator.getDuration() / collapseSpeedUpFactor));
}
+ if (mFixedDuration != NO_FIXED_DURATION) {
+ animator.setDuration(mFixedDuration);
+ }
}
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -1249,4 +1255,14 @@ public abstract class PanelView extends FrameLayout {
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
mHeadsUpManager = headsUpManager;
}
+
+ public void setLaunchingNotification(boolean launchingNotification) {
+ mLaunchingNotification = launchingNotification;
+ }
+
+ public void collapseWithDuration(int animationDuration) {
+ mFixedDuration = animationDuration;
+ collapse(false /* delayed */, 1.0f /* speedUpFactor */);
+ mFixedDuration = NO_FIXED_DURATION;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index a54b26589628..7d8455002300 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -100,6 +100,8 @@ import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
+import android.text.SpannedString;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -205,6 +207,7 @@ import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -586,6 +589,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private NavigationBarFragment mNavigationBar;
private View mNavigationBarView;
+ private ActivityLaunchAnimator mActivityLaunchAnimator;
@Override
public void start() {
@@ -755,6 +759,10 @@ public class StatusBar extends SystemUI implements DemoMode,
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
+ mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
+ this::collapsePanel,
+ mNotificationPanel,
+ mStackScroller);
mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener,
key -> {
try {
@@ -2796,7 +2804,8 @@ public class StatusBar extends SystemUI implements DemoMode,
intent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
int result = ActivityManager.START_CANCELED;
- ActivityOptions options = new ActivityOptions(getActivityOptions());
+ ActivityOptions options = new ActivityOptions(getActivityOptions(
+ null /* sourceNotification */));
options.setDisallowEnterPictureInPictureWhileLaunching(
disallowEnterPictureInPictureWhileLaunching);
if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
@@ -4911,6 +4920,7 @@ public class StatusBar extends SystemUI implements DemoMode,
ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
+ int launchResult = ActivityManager.START_CANCELED;
if (intent != null) {
// If we are launching a work activity and require to launch
// separate work challenge, we defer the activity action and cancel
@@ -4925,12 +4935,30 @@ public class StatusBar extends SystemUI implements DemoMode,
notificationKey)) {
// Show work challenge, do not run PendingIntent and
// remove notification
+ collapsePanel();
return;
}
}
}
+ Intent fillInIntent = null;
+ Entry entry = row.getEntry();
+ CharSequence remoteInputText = null;
+ RemoteInputController controller = mRemoteInputManager.getController();
+ if (controller.isRemoteInputActive(entry)) {
+ remoteInputText = row.getActiveRemoteInputText();
+ }
+ if (TextUtils.isEmpty(remoteInputText)
+ && !TextUtils.isEmpty(entry.remoteInputText)) {
+ remoteInputText = entry.remoteInputText;
+ }
+ if (!TextUtils.isEmpty(remoteInputText)
+ && !controller.isSpinning(entry.key)) {
+ fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
+ remoteInputText.toString());
+ }
try {
- intent.send(null, 0, null, null, null, null, getActivityOptions());
+ launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
+ null, null, getActivityOptions(row));
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -4942,6 +4970,13 @@ public class StatusBar extends SystemUI implements DemoMode,
mAssistManager.hideAssist();
}
}
+ if (shouldCollapse(launchResult)) {
+ if (Looper.getMainLooper().isCurrentThread()) {
+ collapsePanel();
+ } else {
+ mStackScroller.post(this::collapsePanel);
+ }
+ }
try {
mBarService.onNotificationClick(notificationKey);
@@ -4964,19 +4999,45 @@ public class StatusBar extends SystemUI implements DemoMode,
new Thread(runnable).start();
}
- if (!mNotificationPanel.isFullyCollapsed()) {
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
- true /* delayed */);
- visibilityChanged(false);
-
- return true;
- } else {
- return false;
- }
+ return !mNotificationPanel.isFullyCollapsed();
}, afterKeyguardGone);
}
+ private boolean shouldCollapse(int launchResult) {
+ return mState != StatusBarState.SHADE
+ || (launchResult != ActivityManager.START_TASK_TO_FRONT
+ && launchResult != ActivityManager.START_SUCCESS);
+ }
+
+ public void onExpandAnimationFinished() {
+ if (!isPresenterFullyCollapsed()) {
+ instantCollapseNotificationPanel();
+ visibilityChanged(false);
+ }
+ }
+
+ public void collapsePanel(boolean animate) {
+ if (animate) {
+ collapsePanel();
+ } else if (!isPresenterFullyCollapsed()) {
+ instantCollapseNotificationPanel();
+ visibilityChanged(false);
+ }
+ }
+
+ private boolean collapsePanel() {
+ if (!mNotificationPanel.isFullyCollapsed()) {
+ // close the shade if it was open
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
+ true /* delayed */);
+ visibilityChanged(false);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
private void removeNotification(StatusBarNotification notification) {
// We have to post it to the UI thread for synchronization
mHandler.post(() -> {
@@ -5059,15 +5120,20 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override
- public void startNotificationGutsIntent(final Intent intent, final int appUid) {
+ public void startNotificationGutsIntent(final Intent intent, final int appUid,
+ ExpandableNotificationRow row) {
dismissKeyguardThenExecute(() -> {
AsyncTask.execute(() -> {
- TaskStackBuilder.create(mContext)
+ int launchResult = TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
- .startActivities(getActivityOptions(),
+ .startActivities(getActivityOptions(row),
new UserHandle(UserHandle.getUserId(appUid)));
+ if (shouldCollapse(launchResult)) {
+ // Putting it back on the main thread, since we're touching views
+ mStatusBarWindow.post(() -> animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
+ }
});
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
return true;
}, false /* afterKeyguardGone */);
}
@@ -5193,7 +5259,8 @@ public class StatusBar extends SystemUI implements DemoMode,
} catch (RemoteException e) {
}
try {
- intent.send(null, 0, null, null, null, null, getActivityOptions());
+ intent.send(null, 0, null, null, null, null, getActivityOptions(
+ null /* sourceNotification */));
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -5206,16 +5273,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}).start();
- if (!mNotificationPanel.isFullyCollapsed()) {
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
- true /* delayed */);
- visibilityChanged(false);
-
- return true;
- } else {
- return false;
- }
+ return collapsePanel();
}, afterKeyguardGone);
}
@@ -5230,10 +5288,15 @@ public class StatusBar extends SystemUI implements DemoMode,
return true;
}
- protected Bundle getActivityOptions() {
+ protected Bundle getActivityOptions(ExpandableNotificationRow sourceNotification) {
+ ActivityOptions options;
+ if (sourceNotification != null) {
+ options = mActivityLaunchAnimator.getLaunchAnimation(sourceNotification);
+ } else {
+ options = ActivityOptions.makeBasic();
+ }
// Anything launched from the notification shade should always go into the secondary
// split-screen windowing mode.
- final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
return options.toBundle();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 4accd86cce98..f7d0967c2378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -88,6 +88,7 @@ public class StatusBarWindowView extends FrameLayout {
private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
private boolean mTouchCancelled;
private boolean mTouchActive;
+ private boolean mExpandAnimationRunning;
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -267,7 +268,7 @@ public class StatusBarWindowView extends FrameLayout {
|| ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
setTouchActive(false);
}
- if (mTouchCancelled) {
+ if (mTouchCancelled || mExpandAnimationRunning) {
return false;
}
mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
@@ -388,6 +389,10 @@ public class StatusBarWindowView extends FrameLayout {
}
}
+ public void setExpandAnimationRunning(boolean expandAnimationRunning) {
+ mExpandAnimationRunning = expandAnimationRunning;
+ }
+
public class LayoutParams extends FrameLayout.LayoutParams {
public boolean ignoreRightInset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index b63c1da59cba..179c0d57aa50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -169,6 +169,10 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
}
+ public CharSequence getText() {
+ return mEditText.getText();
+ }
+
public static RemoteInputView inflate(Context context, ViewGroup root,
NotificationData.Entry entry,
RemoteInputController controller) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index ebf4cda457e7..424858a86e58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -68,6 +68,8 @@ public class AmbientState {
private boolean mUnlockHintRunning;
private boolean mQsCustomizerShowing;
private int mIntrinsicPadding;
+ private int mExpandAnimationTopChange;
+ private ExpandableNotificationRow mExpandingNotification;
public AmbientState(Context context) {
reload(context);
@@ -77,9 +79,25 @@ public class AmbientState {
* Reload the dimens e.g. if the density changed.
*/
public void reload(Context context) {
- mZDistanceBetweenElements = Math.max(1, context.getResources()
+ mZDistanceBetweenElements = getZDistanceBetweenElements(context);
+ mBaseZHeight = getBaseHeight(mZDistanceBetweenElements);
+ }
+
+ private static int getZDistanceBetweenElements(Context context) {
+ return Math.max(1, context.getResources()
.getDimensionPixelSize(R.dimen.z_distance_between_notifications));
- mBaseZHeight = 4 * mZDistanceBetweenElements;
+ }
+
+ private static int getBaseHeight(int zdistanceBetweenElements) {
+ return 4 * zdistanceBetweenElements;
+ }
+
+ /**
+ * @return the launch height for notifications that are launched
+ */
+ public static int getNotificationLaunchHeight(Context context) {
+ int zDistance = getZDistanceBetweenElements(context);
+ return getBaseHeight(zDistance) * 2;
}
/**
@@ -202,7 +220,8 @@ public class AmbientState {
}
public int getInnerHeight() {
- return Math.max(Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding, mLayoutMinHeight);
+ return Math.max(Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding
+ - mExpandAnimationTopChange, mLayoutMinHeight);
}
public boolean isShadeExpanded() {
@@ -380,4 +399,20 @@ public class AmbientState {
public boolean isDozingAndNotPulsing(ExpandableNotificationRow row) {
return isDark() && !isPulsing(row.getEntry());
}
+
+ public void setExpandAnimationTopChange(int expandAnimationTopChange) {
+ mExpandAnimationTopChange = expandAnimationTopChange;
+ }
+
+ public void setExpandingNotification(ExpandableNotificationRow row) {
+ mExpandingNotification = row;
+ }
+
+ public ExpandableNotificationRow getExpandingNotification() {
+ return mExpandingNotification;
+ }
+
+ public int getExpandAnimationTopChange() {
+ return mExpandAnimationTopChange;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
index 0650e23db883..3bf7d892ea0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
@@ -467,4 +467,21 @@ public class ExpandableViewState extends ViewState {
return getChildTag(view, TAG_END_HEIGHT);
}
}
+
+ @Override
+ public void cancelAnimations(View view) {
+ super.cancelAnimations(view);
+ Animator animator = getChildTag(view, TAG_ANIMATOR_HEIGHT);
+ if (animator != null) {
+ animator.cancel();
+ }
+ animator = getChildTag(view, TAG_ANIMATOR_SHADOW_ALPHA);
+ if (animator != null) {
+ animator.cancel();
+ }
+ animator = getChildTag(view, TAG_ANIMATOR_TOP_INSET);
+ if (animator != null) {
+ animator.cancel();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 53e470938f3f..ad8a0eb98ead 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.stack;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -728,7 +730,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void updateClippingToTopRoundedCorner() {
- Float clipStart = (float) mTopPadding;
+ Float clipStart = (float) mTopPadding + mAmbientState.getExpandAnimationTopChange();
Float clipEnd = clipStart + mCornerRadius;
boolean first = true;
for (int i = 0; i < getChildCount(); i++) {
@@ -2988,6 +2990,17 @@ public class NotificationStackScrollLayout extends ViewGroup
&& (mIsExpanded || isPinnedHeadsUp(child)), child);
}
+ @Override
+ public void setExpandingNotification(ExpandableNotificationRow row) {
+ mAmbientState.setExpandingNotification(row);
+ requestChildrenUpdate();
+ }
+
+ @Override
+ public void applyExpandAnimationParams(ExpandAnimationParameters params) {
+ mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange());
+ requestChildrenUpdate();
+ }
private void updateAnimationState(boolean running, View child) {
if (child instanceof ExpandableNotificationRow) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 2ce6df275588..d68a7b1dc205 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -130,7 +130,8 @@ public class StackScrollAlgorithm {
private void updateClipping(StackScrollState resultState,
StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding()
- + ambientState.getStackTranslation() : 0;
+ + ambientState.getStackTranslation() + ambientState.getExpandAnimationTopChange()
+ : 0;
float previousNotificationEnd = 0;
float previousNotificationStart = 0;
int childCount = algorithmState.visibleChildren.size();
@@ -320,6 +321,10 @@ public class StackScrollAlgorithm {
lastView = v;
}
}
+ ExpandableNotificationRow expandingNotification = ambientState.getExpandingNotification();
+ state.indexOfExpandingNotification = expandingNotification != null
+ ? state.visibleChildren.indexOf(expandingNotification)
+ : -1;
}
private float getPaddingForValue(Float increasedPadding) {
@@ -381,6 +386,9 @@ public class StackScrollAlgorithm {
childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
float inset = ambientState.getTopPadding() + ambientState.getStackTranslation();
+ if (i < algorithmState.getIndexOfExpandingNotification()) {
+ inset += ambientState.getExpandAnimationTopChange();
+ }
if (child.mustStayOnScreen() && childViewState.yTranslation >= 0) {
// Even if we're not scrolled away we're in view and we're also not in the
// shelf. We can relax the constraints and let us scroll off the top!
@@ -394,7 +402,7 @@ public class StackScrollAlgorithm {
childViewState.yTranslation = ambientState.getInnerHeight() - childHeight
+ ambientState.getStackTranslation() * 0.25f;
} else {
- clampPositionToShelf(childViewState, ambientState);
+ clampPositionToShelf(child, childViewState, ambientState);
}
currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
@@ -492,10 +500,12 @@ public class StackScrollAlgorithm {
* Clamp the height of the child down such that its end is at most on the beginning of
* the shelf.
*
+ * @param child
* @param childViewState the view state of the child
* @param ambientState the ambient state
*/
- private void clampPositionToShelf(ExpandableViewState childViewState,
+ private void clampPositionToShelf(ExpandableView child,
+ ExpandableViewState childViewState,
AmbientState ambientState) {
if (ambientState.getShelf() == null) {
return;
@@ -505,7 +515,7 @@ public class StackScrollAlgorithm {
- ambientState.getShelf().getIntrinsicHeight();
childViewState.yTranslation = Math.min(childViewState.yTranslation, shelfStart);
if (childViewState.yTranslation >= shelfStart) {
- childViewState.hidden = true;
+ childViewState.hidden = !child.isExpandAnimationRunning();
childViewState.inShelf = true;
childViewState.headsUpIsVisible = false;
}
@@ -602,6 +612,7 @@ public class StackScrollAlgorithm {
* The padding after each child measured in pixels.
*/
public final HashMap<ExpandableView, Float> paddingMap = new HashMap<>();
+ private int indexOfExpandingNotification;
public int getPaddingAfterChild(ExpandableView child) {
Float padding = paddingMap.get(child);
@@ -611,6 +622,10 @@ public class StackScrollAlgorithm {
}
return (int) padding.floatValue();
}
+
+ public int getIndexOfExpandingNotification() {
+ return indexOfExpandingNotification;
+ }
}
}