Merge changes from topic "all-apps-arrow" into ub-launcher3-master
* changes:
Add all apps education bounce animation
Update vertical drag handle (all apps arrow)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index e62de18..98eb29a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -42,7 +42,6 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateListener;
-import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
@@ -172,7 +171,7 @@
mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen));
ObjectAnimator dragHandleAnim = ObjectAnimator.ofInt(
- mActivity.findViewById(R.id.scrim_view), ScrimView.DRAG_HANDLE_ALPHA, 0);
+ mActivity.getScrimView(), ScrimView.DRAG_HANDLE_ALPHA, 0);
dragHandleAnim.setInterpolator(Interpolators.ACCEL_2);
anim.play(dragHandleAnim);
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 8d42c4a..dcc85d5 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -66,9 +66,6 @@
docked_stack_divider_thickness - 2 * docked_stack_divider_insets -->
<dimen name="multi_window_task_divider_size">10dp</dimen>
- <!-- same as vertical_drag_handle_size -->
- <dimen name="shelf_surface_offset">24dp</dimen>
-
<!-- Assistant Gestures -->
<!-- Distance from the vertical edges of the screen in which assist gestures are recognized -->
<dimen name="gestures_assistant_width">48dp</dimen>
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index ba99016..1f1a999 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -33,9 +33,6 @@
import java.lang.annotation.Retention;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
public class LayoutUtils {
private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
@@ -68,7 +65,7 @@
// UI when shown.
extraSpace = 0;
} else {
- extraSpace = getDefaultSwipeHeight(context, dp) + dp.verticalDragHandleSizePx
+ extraSpace = getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight
+ res.getDimensionPixelSize(
R.dimen.dynamic_grid_hotseat_extra_vertical_size)
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 14c458e..c2ccd90 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -88,7 +88,6 @@
private float mShiftRange;
- private final float mShelfOffset;
private float mTopOffset;
private float mShelfTop;
private float mShelfTopAtThreshold;
@@ -110,7 +109,6 @@
mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mShelfOffset = context.getResources().getDimension(R.dimen.shelf_surface_offset);
// Just assume the easiest UI for now, until we have the proper layout information.
mDrawingFlatColor = true;
}
@@ -179,7 +177,7 @@
Math.min(hotseatSize, LayoutUtils.getDefaultSwipeHeight(context, dp));
mDragHandleProgress = 1 - (dragHandleTop / mShiftRange);
}
- mTopOffset = dp.getInsets().top - mShelfOffset;
+ mTopOffset = dp.getInsets().top - mDragHandleSize.y;
mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
}
updateColors();
@@ -190,12 +188,15 @@
@Override
public void updateColors() {
super.updateColors();
+ mDragHandleOffset = 0;
if (mDrawingFlatColor) {
- mDragHandleOffset = 0;
return;
}
- mDragHandleOffset = mShelfOffset - mDragHandleSize;
+ if (mProgress < mDragHandleProgress) {
+ mDragHandleOffset = mShiftRange * (mDragHandleProgress - mProgress);
+ }
+
if (mProgress >= SCRIM_CATCHUP_THRESHOLD) {
mShelfTop = mShiftRange * mProgress + mTopOffset;
} else {
@@ -231,10 +232,6 @@
(float) 0, LINEAR));
mRemainingScreenColor = setColorAlphaBound(mScrimColor, remainingScrimAlpha);
}
-
- if (mProgress < mDragHandleProgress) {
- mDragHandleOffset += mShiftRange * (mDragHandleProgress - mProgress);
- }
}
@Override
@@ -290,4 +287,9 @@
mPaint.setColor(mShelfColor);
canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint);
}
+
+ @Override
+ public float getVisualTop() {
+ return mShelfTop;
+ }
}
diff --git a/res/drawable-v24/drag_handle_indicator_shadow.xml b/res/drawable-v24/drag_handle_indicator_shadow.xml
new file mode 100644
index 0000000..774bc38
--- /dev/null
+++ b/res/drawable-v24/drag_handle_indicator_shadow.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<com.android.launcher3.graphics.ShadowDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/drag_handle_indicator_no_shadow"
+ android:elevation="@dimen/vertical_drag_handle_elevation" />
diff --git a/res/drawable/drag_handle_indicator.xml b/res/drawable/drag_handle_indicator.xml
deleted file mode 100644
index b01b84a..0000000
--- a/res/drawable/drag_handle_indicator.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/vertical_drag_handle_size"
- android:height="@dimen/vertical_drag_handle_size"
- android:viewportWidth="36.0"
- android:viewportHeight="36.0" >
-
- <group
- android:translateX="11.5"
- android:translateY="11.5">
- <path
- android:pathData="M2 8.5L6.5 4L11 8.5"
- android:strokeColor="?attr/workspaceAmbientShadowColor"
- android:strokeWidth="3.6"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
-
- <path
- android:pathData="M2 8.5L6.5 4L11 8.5"
- android:strokeColor="?attr/workspaceTextColor"
- android:strokeWidth="1.8"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
-</vector>
diff --git a/res/drawable/drag_handle_indicator_no_shadow.xml b/res/drawable/drag_handle_indicator_no_shadow.xml
new file mode 100644
index 0000000..341e60c
--- /dev/null
+++ b/res/drawable/drag_handle_indicator_no_shadow.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/vertical_drag_handle_width"
+ android:height="@dimen/vertical_drag_handle_height"
+ android:viewportWidth="18.0"
+ android:viewportHeight="6.0"
+ android:tint="?attr/workspaceTextColor" >
+
+ <path
+ android:pathData="M17,6c-0.15,0-0.3-0.03-0.45-0.11L9,2.12L1.45,5.89c-0.5,0.25-1.09,
+ 0.05-1.34-0.45S0.06,4.35,0.55,4.11l8-4c0.28-0.14,0.61-0.14,0.89,0l8,4c0.49,0.25,0.69,
+ 0.85,0.45,1.34C17.72,5.8,17.37,6,17,6z"
+ android:fillColor="@android:color/white" />
+</vector>
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index ab6c960..de13277 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -57,7 +57,7 @@
<com.android.launcher3.pageindicators.WorkspacePageIndicator
android:id="@+id/page_indicator"
android:layout_width="match_parent"
- android:layout_height="@dimen/vertical_drag_handle_size"
+ android:layout_height="@dimen/workspace_page_indicator_height"
android:layout_gravity="bottom|center_horizontal"
android:theme="@style/HomeScreenElementTheme" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 271511e..0b589a2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -20,7 +20,6 @@
<!-- Dynamic Grid -->
<dimen name="dynamic_grid_edge_margin">8dp</dimen>
- <dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
<!-- Minimum space between workspace and hotseat in spring loaded mode -->
<dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
@@ -36,10 +35,18 @@
<dimen name="dynamic_grid_hotseat_extra_vertical_size">34dp</dimen>
<dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
+ <!-- Workspace page indicator -->
+ <dimen name="workspace_page_indicator_height">24dp</dimen>
+ <dimen name="workspace_page_indicator_line_height">1dp</dimen>
+ <dimen name="workspace_page_indicator_overlap_workspace">0dp</dimen>
+
<!-- Hotseat/all-apps scrim -->
<dimen name="all_apps_scrim_blur">4dp</dimen>
- <dimen name="vertical_drag_handle_size">24dp</dimen>
- <dimen name="vertical_drag_handle_overlap_workspace">0dp</dimen>
+ <dimen name="vertical_drag_handle_width">18dp</dimen>
+ <dimen name="vertical_drag_handle_height">6dp</dimen>
+ <dimen name="vertical_drag_handle_elevation">1dp</dimen>
+ <dimen name="vertical_drag_handle_touch_size">48dp</dimen>
+ <dimen name="vertical_drag_handle_padding_in_vertical_bar_layout">16dp</dimen>
<!-- Drop target bar -->
<dimen name="dynamic_grid_drop_target_size">48dp</dimen>
diff --git a/res/values/drawables.xml b/res/values/drawables.xml
index 9c57ec1..7d63142 100644
--- a/res/values/drawables.xml
+++ b/res/values/drawables.xml
@@ -18,4 +18,5 @@
<drawable name="ic_remove_shadow">@drawable/ic_remove_no_shadow</drawable>
<drawable name="ic_uninstall_shadow">@drawable/ic_uninstall_no_shadow</drawable>
<drawable name="ic_block_shadow">@drawable/ic_block_no_shadow</drawable>
+ <drawable name="all_apps_arrow_shadow">@drawable/drag_handle_indicator_no_shadow</drawable>
</resources>
\ No newline at end of file
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c049069..4e1e586 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -76,9 +76,9 @@
public float workspaceSpringLoadShrinkFactor;
public final int workspaceSpringLoadedBottomSpace;
- // Drag handle
- public final int verticalDragHandleSizePx;
- private final int verticalDragHandleOverlapWorkspace;
+ // Workspace page indicator
+ public final int workspacePageIndicatorHeight;
+ private final int mWorkspacePageIndicatorOverlapWorkspace;
// Workspace icons
public int iconSizePx;
@@ -190,10 +190,10 @@
cellLayoutBottomPaddingPx = 0;
}
- verticalDragHandleSizePx = res.getDimensionPixelSize(
- R.dimen.vertical_drag_handle_size);
- verticalDragHandleOverlapWorkspace =
- res.getDimensionPixelSize(R.dimen.vertical_drag_handle_overlap_workspace);
+ workspacePageIndicatorHeight = res.getDimensionPixelSize(
+ R.dimen.workspace_page_indicator_height);
+ mWorkspacePageIndicatorOverlapWorkspace =
+ res.getDimensionPixelSize(R.dimen.workspace_page_indicator_overlap_workspace);
iconDrawablePaddingOriginalPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
@@ -211,7 +211,7 @@
hotseatBarSidePaddingEndPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
// Add a bit of space between nav bar and hotseat in vertical bar layout.
- hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? verticalDragHandleSizePx : 0;
+ hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
hotseatBarSizePx = ResourceUtils.pxFromDp(inv.iconSize, dm) + (isVerticalBarLayout()
? (hotseatBarSidePaddingStartPx + hotseatBarSidePaddingEndPx)
: (res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size)
@@ -227,7 +227,7 @@
// in portrait mode closer together by adding more height to the hotseat.
// Note: This calculation was created after noticing a pattern in the design spec.
int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2
- - verticalDragHandleSizePx;
+ - workspacePageIndicatorHeight;
hotseatBarSizePx += extraSpace;
hotseatBarBottomPaddingPx += extraSpace;
@@ -376,7 +376,7 @@
if (!isVerticalLayout) {
int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx
- - verticalDragHandleSizePx - edgeMarginPx;
+ - workspacePageIndicatorHeight - edgeMarginPx;
float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace;
workspaceSpringLoadShrinkFactor = Math.min(
res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f,
@@ -480,14 +480,14 @@
padding.bottom = edgeMarginPx;
if (isSeascape()) {
padding.left = hotseatBarSizePx;
- padding.right = verticalDragHandleSizePx;
+ padding.right = hotseatBarSidePaddingStartPx;
} else {
- padding.left = verticalDragHandleSizePx;
+ padding.left = hotseatBarSidePaddingStartPx;
padding.right = hotseatBarSizePx;
}
} else {
- int paddingBottom = hotseatBarSizePx + verticalDragHandleSizePx
- - verticalDragHandleOverlapWorkspace;
+ int paddingBottom = hotseatBarSizePx + workspacePageIndicatorHeight
+ - mWorkspacePageIndicatorOverlapWorkspace;
if (isTablet) {
// Pad the left and right of the workspace to ensure consistent spacing
// between all icons
@@ -554,7 +554,7 @@
mInsets.top + dropTargetBarSizePx + edgeMarginPx,
mInsets.left + availableWidthPx - edgeMarginPx,
mInsets.top + availableHeightPx - hotseatBarSizePx
- - verticalDragHandleSizePx - edgeMarginPx);
+ - workspacePageIndicatorHeight - edgeMarginPx);
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 03817ad..043ea2f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1140,7 +1140,7 @@
// Setup the drag controller (drop targets have to be added in reverse order in priority)
mDropTargetBar.setup(mDragController);
- mAllAppsController.setupViews(mAppsView);
+ mAllAppsController.setupViews(mAppsView, mScrimView);
}
/**
@@ -1362,6 +1362,10 @@
return mDropTargetBar;
}
+ public ScrimView getScrimView() {
+ return mScrimView;
+ }
+
public LauncherAppWidgetHost getAppWidgetHost() {
return mAppWidgetHost;
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index fc40fa6..3a3de26 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -124,7 +124,7 @@
private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
- private static final int DEFAULT_PAGE = 0;
+ public static final int DEFAULT_PAGE = 0;
private LayoutTransition mLayoutTransition;
@Thunk final WallpaperManager mWallpaperManager;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 7600f52..68b0706 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -123,8 +123,8 @@
// Use a light system UI (dark icons) if all apps is behind at least half of the
// status bar.
- boolean forceChange = shiftCurrent - mScrimView.getDragHandleSize()
- <= mLauncher.getDeviceProfile().getInsets().top / 2;
+ boolean forceChange = Math.min(shiftCurrent, mScrimView.getVisualTop())
+ <= mLauncher.getDeviceProfile().getInsets().top / 2f;
if (forceChange) {
mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme);
} else {
@@ -212,9 +212,9 @@
return AnimationSuccessListener.forRunnable(this::onProgressAnimationEnd);
}
- public void setupViews(AllAppsContainerView appsView) {
+ public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) {
mAppsView = appsView;
- mScrimView = mLauncher.findViewById(R.id.scrim_view);
+ mScrimView = scrimView;
}
/**
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index 0f2ca72..408796f 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -121,7 +121,7 @@
mLinePaint.setAlpha(0);
mLauncher = Launcher.getLauncher(context);
- mLineHeight = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_line_height);
+ mLineHeight = res.getDimensionPixelSize(R.dimen.workspace_page_indicator_line_height);
boolean darkText = WallpaperColorInfo.INSTANCE.get(context).supportsDarkText();
mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 290dbb6..43f30f1 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -17,6 +17,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -50,8 +51,13 @@
@Override
public void onStateTransitionEnd(Launcher launcher) {
- launcher.getStateManager().goToState(NORMAL);
+ LauncherStateManager stateManager = launcher.getStateManager();
Workspace workspace = launcher.getWorkspace();
- workspace.post(workspace::moveToDefaultScreen);
+ boolean willMoveScreens = workspace.getNextPage() != Workspace.DEFAULT_PAGE;
+ stateManager.goToState(NORMAL, true, willMoveScreens ? null
+ : launcher.getScrimView()::startDragHandleEducationAnim);
+ if (willMoveScreens) {
+ workspace.post(workspace::moveToDefaultScreen);
+ }
}
}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 6d204f6..39e1eac 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -22,8 +22,10 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.animation.Animator;
@@ -33,8 +35,10 @@
import android.animation.PropertyValuesHolder;
import android.animation.RectEvaluator;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -98,6 +102,12 @@
private static final int SETTINGS = R.string.settings_button_text;
private static final int ALPHA_CHANNEL_COUNT = 1;
+ private static final long DRAG_HANDLE_BOUNCE_DURATION_MS = 300;
+ // How much to delay before repeating the bounce.
+ private static final long DRAG_HANDLE_BOUNCE_DELAY_MS = 200;
+ // Repeat this many times (i.e. total number of bounces is 1 + this).
+ private static final int DRAG_HANDLE_BOUNCE_REPEAT_COUNT = 2;
+
private final Rect mTempRect = new Rect();
private final int[] mTempPos = new int[2];
@@ -115,10 +125,13 @@
protected int mEndFlatColor;
protected int mEndFlatColorAlpha;
- protected final int mDragHandleSize;
+ protected final Point mDragHandleSize;
+ private final int mDragHandleTouchSize;
+ private final int mDragHandlePaddingInVerticalBarLayout;
protected float mDragHandleOffset;
private final Rect mDragHandleBounds;
private final RectF mHitRect = new RectF();
+ private ObjectAnimator mDragHandleAnim;
private final MultiValueAlpha mMultiValueAlpha;
@@ -136,9 +149,13 @@
mMaxScrimAlpha = 0.7f;
- mDragHandleSize = context.getResources()
- .getDimensionPixelSize(R.dimen.vertical_drag_handle_size);
- mDragHandleBounds = new Rect(0, 0, mDragHandleSize, mDragHandleSize);
+ Resources res = context.getResources();
+ mDragHandleSize = new Point(res.getDimensionPixelSize(R.dimen.vertical_drag_handle_width),
+ res.getDimensionPixelSize(R.dimen.vertical_drag_handle_height));
+ mDragHandleBounds = new Rect(0, 0, mDragHandleSize.x, mDragHandleSize.y);
+ mDragHandleTouchSize = res.getDimensionPixelSize(R.dimen.vertical_drag_handle_touch_size);
+ mDragHandlePaddingInVerticalBarLayout = context.getResources()
+ .getDimensionPixelSize(R.dimen.vertical_drag_handle_padding_in_vertical_bar_layout);
mAccessibilityHelper = createAccessibilityHelper();
ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
@@ -204,6 +221,7 @@
public void setProgress(float progress) {
if (mProgress != progress) {
mProgress = progress;
+ stopDragHandleEducationAnim();
updateColors();
updateDragHandleAlpha();
invalidate();
@@ -251,70 +269,103 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- boolean value = super.onTouchEvent(event);
- if (!value && mDragHandle != null && event.getAction() == ACTION_DOWN
- && mDragHandle.getAlpha() == 255
- && mHitRect.contains(event.getX(), event.getY())) {
-
- final Drawable drawable = mDragHandle;
- mDragHandle = null;
-
- Rect bounds = new Rect(mDragHandleBounds);
- bounds.offset(0, -(int) mDragHandleOffset);
- drawable.setBounds(bounds);
-
- Rect topBounds = new Rect(bounds);
- topBounds.offset(0, -bounds.height() / 2);
-
- Rect invalidateRegion = new Rect(bounds);
- invalidateRegion.top = topBounds.top;
-
- Keyframe frameTop = Keyframe.ofObject(0.6f, topBounds);
- frameTop.setInterpolator(DEACCEL);
- Keyframe frameBot = Keyframe.ofObject(1, bounds);
- frameBot.setInterpolator(ACCEL);
- PropertyValuesHolder holder = PropertyValuesHolder .ofKeyframe("bounds",
- Keyframe.ofObject(0, bounds), frameTop, frameBot);
- holder.setEvaluator(new RectEvaluator());
-
- ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, holder);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- getOverlay().remove(drawable);
- updateDragHandleVisibility(drawable);
+ boolean superHandledTouch = super.onTouchEvent(event);
+ if (event.getAction() == ACTION_DOWN) {
+ if (!superHandledTouch && mHitRect.contains(event.getX(), event.getY())) {
+ if (startDragHandleEducationAnim()) {
+ return true;
}
- });
- anim.addUpdateListener((v) -> invalidate(invalidateRegion));
- getOverlay().add(drawable);
- anim.start();
- return true;
+ }
+ stopDragHandleEducationAnim();
}
- return value;
+ return superHandledTouch;
+ }
+
+ /**
+ * Animates the drag handle to demonstrate how to get to all apps.
+ * @return Whether the animation was started (false if drag handle is invisible).
+ */
+ public boolean startDragHandleEducationAnim() {
+ stopDragHandleEducationAnim();
+
+ if (mDragHandle == null || mDragHandle.getAlpha() != 255) {
+ return false;
+ }
+
+ final Drawable drawable = mDragHandle;
+ mDragHandle = null;
+
+ Rect bounds = new Rect(mDragHandleBounds);
+ bounds.offset(0, -(int) mDragHandleOffset);
+ drawable.setBounds(bounds);
+
+ Rect topBounds = new Rect(bounds);
+ topBounds.offset(0, -bounds.height());
+
+ Rect invalidateRegion = new Rect(bounds);
+ invalidateRegion.top = topBounds.top;
+
+ final float progressToReachTop = 0.6f;
+ Keyframe frameTop = Keyframe.ofObject(progressToReachTop, topBounds);
+ frameTop.setInterpolator(DEACCEL);
+ Keyframe frameBot = Keyframe.ofObject(1, bounds);
+ frameBot.setInterpolator(ACCEL_DEACCEL);
+ PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("bounds",
+ Keyframe.ofObject(0, bounds), frameTop, frameBot);
+ holder.setEvaluator(new RectEvaluator());
+
+ mDragHandleAnim = ObjectAnimator.ofPropertyValuesHolder(drawable, holder);
+ long totalBounceDuration = DRAG_HANDLE_BOUNCE_DURATION_MS + DRAG_HANDLE_BOUNCE_DELAY_MS;
+ // The bounce finishes by this progress, the rest of the duration just delays next bounce.
+ float delayStartProgress = 1f - (float) DRAG_HANDLE_BOUNCE_DELAY_MS / totalBounceDuration;
+ mDragHandleAnim.addUpdateListener((v) -> invalidate(invalidateRegion));
+ mDragHandleAnim.setDuration(totalBounceDuration);
+ mDragHandleAnim.setInterpolator(clampToProgress(LINEAR, 0, delayStartProgress));
+ mDragHandleAnim.setRepeatCount(DRAG_HANDLE_BOUNCE_REPEAT_COUNT);
+ getOverlay().add(drawable);
+
+ mDragHandleAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDragHandleAnim = null;
+ getOverlay().remove(drawable);
+ updateDragHandleVisibility(drawable);
+ }
+ });
+ mDragHandleAnim.start();
+ return true;
+ }
+
+ private void stopDragHandleEducationAnim() {
+ if (mDragHandleAnim != null) {
+ mDragHandleAnim.end();
+ }
}
protected void updateDragHandleBounds() {
DeviceProfile grid = mLauncher.getDeviceProfile();
final int left;
final int width = getMeasuredWidth();
- final int top = getMeasuredHeight() - mDragHandleSize - grid.getInsets().bottom;
+ final int top = getMeasuredHeight() - mDragHandleSize.y - grid.getInsets().bottom;
final int topMargin;
if (grid.isVerticalBarLayout()) {
- topMargin = grid.workspacePadding.bottom;
+ topMargin = grid.workspacePadding.bottom + mDragHandlePaddingInVerticalBarLayout;
if (grid.isSeascape()) {
- left = width - grid.getInsets().right - mDragHandleSize;
+ left = width - grid.getInsets().right - mDragHandleSize.x
+ - mDragHandlePaddingInVerticalBarLayout;
} else {
- left = mDragHandleSize + grid.getInsets().left;
+ left = grid.getInsets().left + mDragHandlePaddingInVerticalBarLayout;
}
} else {
- left = (width - mDragHandleSize) / 2;
+ left = Math.round((width - mDragHandleSize.x) / 2f);
topMargin = grid.hotseatBarSizePx;
}
mDragHandleBounds.offsetTo(left, top - topMargin);
mHitRect.set(mDragHandleBounds);
- float inset = -mDragHandleSize / 2;
- mHitRect.inset(inset, inset);
+ // Inset outwards to increase touch size.
+ mHitRect.inset((mDragHandleSize.x - mDragHandleTouchSize) / 2f,
+ (mDragHandleSize.y - mDragHandleTouchSize) / 2f);
if (mDragHandle != null) {
mDragHandle.setBounds(mDragHandleBounds);
@@ -341,7 +392,7 @@
if (visible != wasVisible) {
if (visible) {
mDragHandle = recycle != null ? recycle :
- mLauncher.getDrawable(R.drawable.drag_handle_indicator);
+ mLauncher.getDrawable(R.drawable.drag_handle_indicator_shadow);
mDragHandle.setBounds(mDragHandleBounds);
updateDragHandleAlpha();
@@ -397,7 +448,7 @@
@Override
protected int getVirtualViewAt(float x, float y) {
- return mDragHandleBounds.contains((int) x, (int) y)
+ return mHitRect.contains((int) x, (int) y)
? DRAG_HANDLE_ID : INVALID_ID;
}
@@ -470,7 +521,10 @@
}
}
- public int getDragHandleSize() {
- return mDragHandleSize;
+ /**
+ * @return The top of this scrim view, or {@link Float#MAX_VALUE} if there's no distinct top.
+ */
+ public float getVisualTop() {
+ return Float.MAX_VALUE;
}
}