Add long swipe from app to overview gesture (with flag).

High level:
 - As you swipe up from an app (OtherActivityInputConsumer),
   a state transition animation to All Apps is created in
   AnimatorControllerWithResistance. The animation is played
   alongside the Recents resistance animation (i.e. past the
   settling point of Overview, which is at mCurrentShift 1).
 - The actual state transition to All Apps only happens if you
   release your finger in the "all apps region." This is set to
   mCurrentShift 2, so double the distance that Overview rests.
 - A haptic plays whenever you enter or exit this region, and
   the all apps animation is set to 0 until the region is
   active. This is so it's clear that something different is
   happening.
 - The panel that was previously used for tablets is now used
   for phones during this transition. It comes in at full
   opacity when you enter the region, and the contents (apps
   and search suggestions) fade in as you continue swiping.
 - The only gesture that is recognized in the all apps region
   is a fling downwards, which will return you to the previous
   app. Otherwise a left/right/up fling or slow release will
   finish the all apps transition.
 - The threshold is ignored if the flag is disabled (default)
   or if FallbackActivityInterface is active.

Flag:
The threshold is ignored if ENABLE_ALL_APPS_FROM_OVERVIEW is
disabled (default).

Bug: 259619990
Bug: 275132633
Test: Manual with and without the flag enabled
Change-Id: Ie311b77252416d97677b2c56fad61dfd392b6fe8
This commit is contained in:
Andy Wickham
2023-04-19 07:08:44 -07:00
parent 773c5c1760
commit 830e4b7ce0
20 changed files with 278 additions and 46 deletions

View File

@@ -40,6 +40,7 @@ import android.os.Parcelable;
import android.os.Process;
import android.os.UserManager;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -101,6 +102,20 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
OnDeviceProfileChangeListener, PersonalWorkSlidingTabStrip.OnActivePageChangedListener,
ScrimView.ScrimDrawingController {
public static final FloatProperty<ActivityAllAppsContainerView<?>> BOTTOM_SHEET_ALPHA =
new FloatProperty<>("bottomSheetAlpha") {
@Override
public Float get(ActivityAllAppsContainerView<?> containerView) {
return containerView.mBottomSheetAlpha;
}
@Override
public void setValue(ActivityAllAppsContainerView<?> containerView, float v) {
containerView.setBottomSheetAlpha(v);
}
};
public static final float PULL_MULTIPLIER = .02f;
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
@@ -159,6 +174,8 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
private ScrimView mScrimView;
private int mHeaderColor;
private int mBottomSheetBackgroundColor;
private float mBottomSheetAlpha = 1f;
private boolean mForceBottomSheetVisible;
private int mTabsProtectionAlpha;
@Nullable private AllAppsTransitionController mAllAppsTransitionController;
@@ -258,7 +275,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
final TypedValue value = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.colorBackground, value, true);
mBottomSheetBackgroundColor = value.data;
updateBackground(mActivityContext.getDeviceProfile());
updateBackgroundVisibility(mActivityContext.getDeviceProfile());
mSearchUiManager.initializeSearch(this);
}
@@ -282,6 +299,16 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
return mBottomSheetBackground;
}
/**
* Temporarily force the bottom sheet to be visible on non-tablets.
*
* @param force {@code true} means bottom sheet will be visible on phones until {@code reset()}.
**/
public void forceBottomSheetVisible(boolean force) {
mForceBottomSheetVisible = force;
updateBackgroundVisibility(mActivityContext.getDeviceProfile());
}
public View getSearchView() {
return mSearchContainer;
}
@@ -408,6 +435,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
if (mHeader != null && mHeader.getVisibility() == VISIBLE) {
mHeader.reset(animate);
}
forceBottomSheetVisible(false);
// Reset the base recycler view after transitioning home.
updateHeaderScroll(0);
if (exitSearch) {
@@ -830,7 +858,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
holder.mRecyclerView.getRecycledViewPool().clear();
}
}
updateBackground(dp);
updateBackgroundVisibility(dp);
int navBarScrimColor = Themes.getNavBarScrimColor(mActivityContext);
if (mNavBarScrimPaint.getColor() != navBarScrimColor) {
@@ -839,13 +867,19 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
}
}
protected void updateBackground(DeviceProfile deviceProfile) {
mBottomSheetBackground.setVisibility(deviceProfile.isTablet ? View.VISIBLE : View.GONE);
protected void updateBackgroundVisibility(DeviceProfile deviceProfile) {
boolean visible = deviceProfile.isTablet || mForceBottomSheetVisible;
mBottomSheetBackground.setVisibility(visible ? View.VISIBLE : View.GONE);
// Note: For tablets, the opaque background and header protection are added in drawOnScrim.
// For the taskbar entrypoint, the scrim is drawn differently, so a static background is
// added in TaskbarAllAppsContainerView and header protection is not yet supported.
}
private void setBottomSheetAlpha(float alpha) {
// Bottom sheet alpha is always 1 for tablets.
mBottomSheetAlpha = mActivityContext.getDeviceProfile().isTablet ? 1f : alpha;
}
private void onAppsUpdated() {
mHasWorkApps = Stream.of(mAllAppsStore.getApps()).anyMatch(mWorkManager.getMatcher());
if (TestProtocol.sDebugTracing) {
@@ -1148,8 +1182,8 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
@Override
public void drawOnScrimWithScale(Canvas canvas, float scale) {
final boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
final View panel = mBottomSheetBackground;
final boolean hasBottomSheet = panel.getVisibility() == VISIBLE;
final float translationY = ((View) panel.getParent()).getTranslationY();
final float horizontalScaleOffset = (1 - scale) * panel.getWidth() / 2;
@@ -1160,8 +1194,9 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
final float leftWithScale = panel.getLeft() + horizontalScaleOffset;
final float rightWithScale = panel.getRight() - horizontalScaleOffset;
// Draw full background panel for tablets.
if (isTablet) {
if (hasBottomSheet) {
mHeaderPaint.setColor(mBottomSheetBackgroundColor);
mHeaderPaint.setAlpha((int) (255 * mBottomSheetAlpha));
mTmpRectF.set(
leftWithScale,
@@ -1192,7 +1227,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
final float headerBottomOffset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
final float headerBottomWithScaleOnPhone = headerBottomNoScale * scale + headerBottomOffset;
final FloatingHeaderView headerView = getFloatingHeaderView();
if (isTablet) {
if (hasBottomSheet) {
// Start adding header protection if search bar or tabs will attach to the top.
if (!FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() || mUsingTabs) {
mTmpRectF.set(
@@ -1219,12 +1254,12 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
}
float left = 0f;
float right = canvas.getWidth();
if (isTablet) {
if (hasBottomSheet) {
left = mBottomSheetBackground.getLeft() + horizontalScaleOffset;
right = mBottomSheetBackground.getRight() - horizontalScaleOffset;
}
final float tabTopWithScale = isTablet
final float tabTopWithScale = hasBottomSheet
? headerBottomWithScaleOnTablet
: headerBottomWithScaleOnPhone;
final float tabBottomWithScale = tabTopWithScale + tabsHeight * scale;
@@ -1263,7 +1298,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
* Returns a view that denotes the visible part of all apps container view.
*/
public View getVisibleContainerView() {
return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
return mBottomSheetBackground.getVisibility() == VISIBLE ? mBottomSheetBackground : this;
}
protected void onInitializeRecyclerView(RecyclerView rv) {