diff --git a/res/values/dimens.xml b/res/values/dimens.xml index fe0b11bb3f..0adafaf7fb 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -92,7 +92,8 @@ 700dp 475dp 50dp - 50dp + 48dp + 48dp 2dp 36dp 16dp diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index deb114765c..5896f5a4de 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1192,7 +1192,7 @@ public class Launcher extends StatefulActivity implements Launche // Setup the drag controller (drop targets have to be added in reverse order in priority) mDropTargetBar.setup(mDragController); - mAllAppsController.setupViews(mAppsView); + mAllAppsController.setupViews(mScrimView, mAppsView); } /** diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index b11b63ed69..47236b6994 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; @@ -44,6 +45,7 @@ import android.view.WindowInsets; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; +import androidx.core.graphics.ColorUtils; import androidx.core.os.BuildCompat; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; @@ -66,6 +68,7 @@ import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.Themes; import com.android.launcher3.views.RecyclerViewFastScroller; +import com.android.launcher3.views.ScrimView; import com.android.launcher3.views.SpringRelativeLayout; import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener; @@ -73,13 +76,16 @@ import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePag * The all apps view container. */ public class AllAppsContainerView extends SpringRelativeLayout implements DragSource, - Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener { + Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener, + ScrimView.ScrimDrawingController { private static final float FLING_VELOCITY_MULTIPLIER = 1000f; // Starts the springs after at least 25% of the animation has passed. private static final float FLING_ANIMATION_THRESHOLD = 0.25f; + private final Paint mHeaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + protected final BaseDraggingActivity mLauncher; protected final AdapterHolder[] mAH; private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle()); @@ -93,7 +99,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo private View mSearchContainer; private AllAppsPagedView mViewPager; - private FloatingHeaderView mHeader; + protected FloatingHeaderView mHeader; private WorkModeSwitch mWorkModeSwitch; @@ -107,7 +113,14 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo private Rect mInsets = new Rect(); - SearchAdapterProvider mSearchAdapterProvider; + private SearchAdapterProvider mSearchAdapterProvider; + private final int mHeaderTopPadding; + private final int mScrimColor; + private final int mHeaderProtectionColor; + private final float mHeaderThreshold; + private ScrimView mScrimView; + private int mHeaderColor; + public AllAppsContainerView(Context context) { this(context, null); @@ -121,8 +134,19 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo super(context, attrs, defStyleAttr); mLauncher = BaseDraggingActivity.fromContext(context); + + mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor); + mHeaderThreshold = getResources().getDimensionPixelSize( + R.dimen.dynamic_grid_cell_border_spacing); + mHeaderTopPadding = context.getResources() + .getDimensionPixelSize(R.dimen.all_apps_header_top_padding); + int accentColor = Themes.getColorAccent(getContext()); + mHeaderProtectionColor = ColorUtils.blendARGB(mScrimColor, accentColor, .3f); + mLauncher.addOnDeviceProfileChangeListener(this); + + mSearchAdapterProvider = mLauncher.createSearchAdapterProvider(this); mSearchQueryBuilder = new SpannableStringBuilder(); Selection.setSelection(mSearchQueryBuilder, 0); @@ -300,6 +324,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo } // Reset the search bar and base recycler view after transitioning home mSearchUiManager.resetSearch(); + updateHeaderScroll(0); } @Override @@ -625,6 +650,26 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo outRect.offset(0, (int) getTranslationY()); } + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + invalidateHeader(); + } + + public void setScrimView(ScrimView scrimView) { + mScrimView = scrimView; + } + + @Override + public void drawOnScrim(Canvas canvas) { + mHeaderPaint.setColor(mHeaderColor); + mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor))); + if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) { + canvas.drawRect(0, 0, getWidth(), mHeaderTopPadding + getTranslationY(), + mHeaderPaint); + } + } + public class AdapterHolder { public static final int MAIN = 0; public static final int WORK = 1; @@ -725,4 +770,24 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo return mOverlay; } } + + + protected void updateHeaderScroll(int scrolledOffset) { + float prog = Math.max(0, Math.min(1, (float) scrolledOffset / mHeaderThreshold)); + int headerColor = ColorUtils.setAlphaComponent(mHeaderProtectionColor, (int) (prog * 255)); + if (headerColor != mHeaderColor) { + mHeaderColor = headerColor; + getSearchView().setBackgroundColor(mHeaderColor); + invalidateHeader(); + } + } + + /** + * redraws header protection + */ + public void invalidateHeader() { + if (mScrimView != null) { + mScrimView.invalidate(); + } + } } diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index b1c764c1d1..197d74c401 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -38,6 +38,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BaseRecyclerView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.logging.StatsLogManager; @@ -52,6 +53,7 @@ import java.util.List; public class AllAppsRecyclerView extends BaseRecyclerView { private static final String TAG = "AllAppsContainerView"; private static final boolean DEBUG = false; + private final Launcher mLauncher; private AlphabeticalAppsList mApps; private final int mNumAppsPerRow; @@ -87,6 +89,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView { R.dimen.all_apps_empty_search_bg_top_offset); mNumAppsPerRow = LauncherAppState.getIDP(context).numColumns; mFastScrollHelper = new AllAppsFastScrollHelper(this); + mLauncher = Launcher.getLauncher(context); } /** @@ -199,6 +202,12 @@ public class AllAppsRecyclerView extends BaseRecyclerView { } } + @Override + public void onScrolled(int dx, int dy) { + super.onScrolled(dx, dy); + mLauncher.getAppsView().updateHeaderScroll(getCurrentScrollY()); + } + @Override public boolean onInterceptTouchEvent(MotionEvent e) { boolean result = super.onInterceptTouchEvent(e); @@ -410,7 +419,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView { /** * Returns the available scroll height: - * AvailableScrollHeight = Total height of the all items - last page height + * AvailableScrollHeight = Total height of the all items - last page height */ @Override protected int getAvailableScrollHeight() { diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index c4c7891d58..90f2d7cde5 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -45,6 +45,7 @@ import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.views.ScrimView; /** * Handles AllApps view transition. @@ -88,6 +89,7 @@ public class AllAppsTransitionController private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent private float mScrollRangeDelta = 0; + private ScrimView mScrimView; public AllAppsTransitionController(Launcher l) { mLauncher = l; @@ -158,7 +160,7 @@ public class AllAppsTransitionController Interpolator interpolator = toState.equals(ALL_APPS) ? (config.userControlled ? ACCEL_2 : ACCEL_0_75) : - (config.userControlled ? DEACCEL_2 : DEACCEL); + (config.userControlled ? DEACCEL_2 : DEACCEL); Animator anim = createSpringAnimation(mProgress, targetProgress); anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator)); @@ -181,19 +183,28 @@ public class AllAppsTransitionController Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR); setter.setViewAlpha(mAppsView, hasAllAppsContent ? 1 : 0, allAppsFade); + + boolean shouldProtectHeader = + ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS; + mScrimView.setDrawingController(shouldProtectHeader ? mAppsView : null); } public AnimatorListenerAdapter getProgressAnimatorListener() { return AnimationSuccessListener.forRunnable(this::onProgressAnimationEnd); } - public void setupViews(AllAppsContainerView appsView) { + /** + * see Launcher#setupViews + */ + public void setupViews(ScrimView scrimView, AllAppsContainerView appsView) { + mScrimView = scrimView; mAppsView = appsView; if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && Utilities.ATLEAST_R) { mLauncher.getSystemUiController().updateUiState(UI_STATE_ALLAPPS, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } + mAppsView.setScrimView(scrimView); } /** diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java index 5387a3ed17..0ba94ab240 100644 --- a/src/com/android/launcher3/views/ScrimView.java +++ b/src/com/android/launcher3/views/ScrimView.java @@ -18,6 +18,7 @@ package com.android.launcher3.views; import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW; import android.content.Context; +import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.util.AttributeSet; @@ -37,13 +38,16 @@ public class ScrimView extends View implements Insettable { private SystemUiController mSystemUiController; + private ScrimDrawingController mDrawingController; + public ScrimView(Context context, AttributeSet attrs) { super(context, attrs); setFocusable(false); } @Override - public void setInsets(Rect insets) { } + public void setInsets(Rect insets) { + } @Override public boolean hasOverlappingRendering() { @@ -62,6 +66,14 @@ public class ScrimView extends View implements Insettable { super.setBackgroundColor(color); } + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (mDrawingController != null) { + mDrawingController.drawOnScrim(canvas); + } + } + @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); @@ -96,4 +108,24 @@ public class ScrimView extends View implements Insettable { return ColorUtils.calculateLuminance( ((ColorDrawable) getBackground()).getColor()) < 0.5f; } + + /** + * Sets drawing controller. Invalidates ScrimView if drawerController has changed. + */ + public void setDrawingController(ScrimDrawingController drawingController) { + if (mDrawingController != drawingController) { + mDrawingController = drawingController; + invalidate(); + } + } + + /** + * A Utility interface allowing for other surfaces to draw on ScrimView + */ + public interface ScrimDrawingController { + /** + * Called inside ScrimView#OnDraw + */ + void drawOnScrim(Canvas canvas); + } }