diff options
15 files changed, 242 insertions, 39 deletions
diff --git a/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png Binary files differnew file mode 100644 index 0000000..85db9c8 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png Binary files differnew file mode 100644 index 0000000..c4941a6 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png Binary files differnew file mode 100644 index 0000000..4618f40 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png Binary files differnew file mode 100644 index 0000000..36e7e45 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png Binary files differnew file mode 100644 index 0000000..c0bf31d --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png diff --git a/packages/SystemUI/res/layout/recents_search_bar.xml b/packages/SystemUI/res/layout/recents_search_bar.xml new file mode 100644 index 0000000..915283e --- /dev/null +++ b/packages/SystemUI/res/layout/recents_search_bar.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 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. +--> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/search_bg_transparent"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:text="@string/recents_search_bar_label" + android:textColor="#99ffffff" + android:textSize="18sp" + android:textAllCaps="true" /> +</FrameLayout> + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index e7959ab..02ba6dd 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -245,6 +245,12 @@ <!-- The amount of space a user has to scroll to dismiss any info panes. --> <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen> + <!-- The height of the search bar space. --> + <dimen name="recents_search_bar_space_height">40dp</dimen> + + <!-- The search bar edge margins. --> + <dimen name="recents_search_bar_space_edge_margins">12dp</dimen> + <!-- Used to calculate the translation animation duration, the expected amount of movement in dps over one second of time. --> <dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 73e5e19..72d14fe 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -511,6 +511,8 @@ <string name="recents_empty_message">RECENTS</string> <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] --> <string name="recents_app_info_button_label">Application Info</string> + <!-- Recents: Temporary string for the button in the recents search bar. [CHAR LIMIT=NONE] --> + <string name="recents_search_bar_label">search</string> <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. --> diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 64770a4..72d9a52 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -29,6 +29,7 @@ public class Constants { public static final boolean EnableTaskFiltering = true; public static final boolean EnableTaskStackClipping = false; public static final boolean EnableInfoPane = true; + public static final boolean EnableSearchButton = false; // This disables the bitmap and icon caches public static final boolean DisableBackgroundCache = false; @@ -84,6 +85,9 @@ public class Constants { public static final int TaskStackOverscrollRange = 150; public static final int FilterStartDelay = 25; + // The amount to inverse scale the movement if we are overscrolling + public static final float TouchOverscrollScaleFactor = 3f; + // The padding will be applied to the smallest dimension, and then applied to all sides public static final float StackPaddingPct = 0.15f; // The overlap height relative to the task height diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 5e5b841..d54df13 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -44,6 +44,8 @@ public class RecentsConfiguration { public int taskStackMaxDim; public int taskViewInfoPaneAnimDuration; public int taskViewRoundedCornerRadiusPx; + public int searchBarSpaceHeightPx; + public int searchBarSpaceEdgeMarginsPx; public boolean launchedWithThumbnailAnimation; @@ -92,6 +94,9 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_animate_task_view_info_pane_duration); taskViewRoundedCornerRadiusPx = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); + searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height); + searchBarSpaceEdgeMarginsPx = + res.getDimensionPixelSize(R.dimen.recents_search_bar_space_edge_margins); } /** Updates the system insets */ @@ -99,6 +104,26 @@ public class RecentsConfiguration { systemInsets.set(insets); } + /** Returns the search bar bounds in the specified orientation */ + public void getSearchBarBounds(int width, int height, + Rect searchBarSpaceBounds, Rect searchBarBounds) { + // Return empty rects if search is not enabled + if (!Constants.DebugFlags.App.EnableSearchButton) { + searchBarSpaceBounds.set(0, 0, 0, 0); + searchBarBounds.set(0, 0, 0, 0); + return; + } + + // Calculate the search bar bounds, and account for the system insets + int edgeMarginPx = searchBarSpaceEdgeMarginsPx; + int availableWidth = width - systemInsets.left - systemInsets.right; + searchBarSpaceBounds.set(0, 0, availableWidth, 2 * edgeMarginPx + searchBarSpaceHeightPx); + + // Inset from the search bar space to get the search bar bounds + searchBarBounds.set(searchBarSpaceBounds); + searchBarBounds.inset(edgeMarginPx, edgeMarginPx); + } + /** Converts from DPs to PXs */ public int pxFromDp(float size) { return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java index 06ca9e2..36b761e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java @@ -66,22 +66,33 @@ class SystemUIMessageHandler extends Handler { Bundle replyData = new Bundle(); TaskViewTransform transform; + // Get the search bar bounds so that we can account for its height in the children + Rect searchBarSpaceBounds = new Rect(); + Rect searchBarBounds = new Rect(); + RecentsConfiguration config = RecentsConfiguration.getInstance(); + config.getSearchBarBounds(windowRect.width(), windowRect.height(), + searchBarSpaceBounds, searchBarBounds); + // Calculate the target task rect for when there is one task // NOTE: Since the nav bar height is already accounted for in the windowRect, don't // pass in a bottom inset stack.addTask(new Task()); - tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0); + tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top - + systemInsets.bottom - searchBarSpaceBounds.height(), 0); tsv.boundScroll(); transform = tsv.getStackTransform(0, tsv.getStackScroll()); + transform.rect.offset(0, searchBarSpaceBounds.height()); replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT, new Rect(transform.rect)); // Also calculate the target task rect when there are multiple tasks stack.addTask(new Task()); - tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0); + tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top - + systemInsets.bottom - searchBarSpaceBounds.height(), 0); tsv.setStackScrollRaw(Integer.MAX_VALUE); tsv.boundScroll(); transform = tsv.getStackTransform(1, tsv.getStackScroll()); + transform.rect.offset(0, searchBarSpaceBounds.height()); replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT, new Rect(transform.rect)); diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java index 7f0d9ee..33ac0a8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java @@ -19,6 +19,8 @@ package com.android.systemui.recents; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.AppGlobals; +import android.app.SearchManager; +import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -26,11 +28,15 @@ import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.text.TextUtils; +import android.util.Log; import java.util.ArrayList; import java.util.List; @@ -45,6 +51,7 @@ public class SystemServicesProxy { PackageManager mPm; IPackageManager mIpm; UserManager mUm; + SearchManager mSm; String mPackage; Bitmap mDummyIcon; @@ -55,6 +62,7 @@ public class SystemServicesProxy { mPm = context.getPackageManager(); mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); mIpm = AppGlobals.getPackageManager(); + mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); mPackage = context.getPackageName(); if (Constants.DebugFlags.App.EnableSystemServicesProxy) { @@ -199,4 +207,28 @@ public class SystemServicesProxy { } return icon; } + + + /** + * Composes an intent to launch the global search activity. + */ + public Intent getGlobalSearchIntent(Rect sourceBounds) { + if (mSm == null) return null; + + // Try and get the global search activity + ComponentName globalSearchActivity = mSm.getGlobalSearchActivity(); + if (globalSearchActivity == null) return null; + + // Bundle the source of the search + Bundle appSearchData = new Bundle(); + appSearchData.putString("source", mPackage); + + // Compose the intent and Start the search activity + Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setComponent(globalSearchActivity); + intent.putExtra(SearchManager.APP_DATA, appSearchData); + intent.setSourceBounds(sourceBounds); + return intent; + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index b054a22..1df4670 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -27,8 +27,11 @@ import android.graphics.Rect; import android.net.Uri; import android.os.UserHandle; import android.provider.Settings; +import android.view.Gravity; +import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; +import android.widget.TextView; import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; @@ -36,6 +39,7 @@ import com.android.systemui.recents.RecentsTaskLoader; import com.android.systemui.recents.model.SpaceNode; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.R; import java.util.ArrayList; @@ -53,11 +57,16 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // The space partitioning root of this container SpaceNode mBSP; + // Search bar view + View mSearchBar; // Recents view callbacks RecentsViewCallbacks mCb; + LayoutInflater mInflater; + public RecentsView(Context context) { super(context); + mInflater = LayoutInflater.from(context); setWillNotDraw(false); } @@ -71,12 +80,22 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV mBSP = n; // Create and add all the stacks for this partition of space. + boolean hasTasks = false; removeAllViews(); ArrayList<TaskStack> stacks = mBSP.getStacks(); for (TaskStack stack : stacks) { TaskStackView stackView = new TaskStackView(getContext(), stack); stackView.setCallbacks(this); addView(stackView); + hasTasks |= (stack.getTaskCount() > 0); + } + + // Create the search bar (and hide it if we have no recent tasks) + if (Constants.DebugFlags.App.EnableSearchButton) { + createSearchBar(); + if (!hasTasks) { + mSearchBar.setVisibility(View.GONE); + } } } @@ -85,29 +104,45 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Get the first stack view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - TaskStackView stackView = (TaskStackView) getChildAt(i); - TaskStack stack = stackView.mStack; - ArrayList<Task> tasks = stack.getTasks(); - - // Get the first task in the stack - if (!tasks.isEmpty()) { - Task task = tasks.get(tasks.size() - 1); - TaskView tv = null; - - // Try and use the first child task view as the source of the launch animation - if (stackView.getChildCount() > 0) { - TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1); - if (stv.getTask() == task) { - tv = stv; + View child = getChildAt(i); + if (child instanceof TaskStackView) { + TaskStackView stackView = (TaskStackView) child; + TaskStack stack = stackView.mStack; + ArrayList<Task> tasks = stack.getTasks(); + + // Get the first task in the stack + if (!tasks.isEmpty()) { + Task task = tasks.get(tasks.size() - 1); + TaskView tv = null; + + // Try and use the first child task view as the source of the launch animation + if (stackView.getChildCount() > 0) { + TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1); + if (stv.getTask() == task) { + tv = stv; + } } + onTaskLaunched(stackView, tv, stack, task); + return true; } - onTaskLaunched(stackView, tv, stack, task); - return true; } } return false; } + /** Creates and adds the search bar */ + void createSearchBar() { + // Create a temporary search bar + mSearchBar = mInflater.inflate(R.layout.recents_search_bar, this, false); + mSearchBar.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onSearchTriggered(); + } + }); + addView(mSearchBar); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); @@ -120,16 +155,26 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup, Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure"); - // We measure our stack views sans the status bar. It will handle the nav bar itself. + // Get the search bar bounds so that we can account for its height in the children + Rect searchBarSpaceBounds = new Rect(); + Rect searchBarBounds = new Rect(); RecentsConfiguration config = RecentsConfiguration.getInstance(); + config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), + searchBarSpaceBounds, searchBarBounds); + if (mSearchBar != null) { + mSearchBar.measure(MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), widthMode), + MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), heightMode)); + } + + // We measure our stack views sans the status bar. It will handle the nav bar itself. int childWidth = width - config.systemInsets.right; - int childHeight = height - config.systemInsets.top; + int childHeight = height - config.systemInsets.top - searchBarSpaceBounds.height(); // Measure each child int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { + View child = getChildAt(i); + if (child instanceof TaskStackView && child.getVisibility() != GONE) { child.measure(MeasureSpec.makeMeasureSpec(childWidth, widthMode), MeasureSpec.makeMeasureSpec(childHeight, heightMode)); } @@ -145,18 +190,30 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup, Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout"); - // We offset our stack views by the status bar height. It will handle the nav bar itself. + // Get the search bar bounds so that we can account for its height in the children + Rect searchBarSpaceBounds = new Rect(); + Rect searchBarBounds = new Rect(); RecentsConfiguration config = RecentsConfiguration.getInstance(); - top += config.systemInsets.top; + config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), + searchBarSpaceBounds, searchBarBounds); + if (mSearchBar != null) { + mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left, + config.systemInsets.top + searchBarSpaceBounds.top, + config.systemInsets.left + mSearchBar.getMeasuredWidth(), + config.systemInsets.top + mSearchBar.getMeasuredHeight()); + } + + // We offset our stack views by the status bar height. It will handle the nav bar itself. + top += config.systemInsets.top + searchBarSpaceBounds.height(); // Layout each child // XXX: Based on the space node for that task view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { - final int width = child.getMeasuredWidth(); - final int height = child.getMeasuredHeight(); + View child = getChildAt(i); + if (child instanceof TaskStackView && child.getVisibility() != GONE) { + int width = child.getMeasuredWidth(); + int height = child.getMeasuredHeight(); child.layout(left, top, left + width, top + height); } } @@ -188,9 +245,12 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Get the first stack view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - TaskStackView stackView = (TaskStackView) getChildAt(i); - if (stackView.closeOpenInfoPanes()) { - return true; + View child = getChildAt(i); + if (child instanceof TaskStackView) { + TaskStackView stackView = (TaskStackView) child; + if (stackView.closeOpenInfoPanes()) { + return true; + } } } } @@ -315,4 +375,24 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV TaskStackBuilder.create(getContext()) .addNextIntentWithParentStack(intent).startActivities(); } + + public void onSearchTriggered() { + // Get the search bar source bounds + Rect searchBarSpaceBounds = new Rect(); + Rect searchBarBounds = new Rect(); + RecentsConfiguration config = RecentsConfiguration.getInstance(); + config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), + searchBarSpaceBounds, searchBarBounds); + + // Get the search intent and start it + Intent searchIntent = RecentsTaskLoader.getInstance().getSystemServicesProxy() + .getGlobalSearchIntent(searchBarBounds); + if (searchIntent != null) { + try { + getContext().startActivity(searchIntent); + } catch (ActivityNotFoundException anfe) { + Console.logError(getContext(), "Could not start Search activity"); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java index 233e38c..a81d01c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java @@ -70,10 +70,8 @@ class TaskInfoView extends FrameLayout { /** Updates the positions of each of the items to fit in the rect specified */ void updateContents(Rect visibleRect) { // Offset the app info button - LayoutParams lp = (LayoutParams) mAppInfoButton.getLayoutParams(); - lp.topMargin = visibleRect.top + - (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2; - requestLayout(); + mAppInfoButton.setTranslationY(visibleRect.top + + (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2); } /** Sets the circular clip radius on this panel */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index ee92b16..a77e61d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -395,9 +395,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return false; } - /** Returns whether the current scroll is out of bounds */ + /** Returns whether the specified scroll is out of bounds */ + boolean isScrollOutOfBounds(int scroll) { + return (scroll < mMinScroll) || (scroll > mMaxScroll); + } boolean isScrollOutOfBounds() { - return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll); + return isScrollOutOfBounds(getStackScroll()); } /** Updates the min and max virtual scroll bounds */ @@ -556,7 +559,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int smallestDimension = Math.min(width, height); int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f); - mStackRect.inset(padding, padding); + if (Constants.DebugFlags.App.EnableSearchButton) { + // Don't need to pad the top since we have some padding on the search bar already + mStackRect.left += padding; + mStackRect.right -= padding; + mStackRect.bottom -= padding; + } else { + mStackRect.inset(padding, padding); + } mStackRectSansPeek.set(mStackRect); mStackRectSansPeek.top += Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height(); @@ -1275,7 +1285,12 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { } } if (mIsScrolling) { - mSv.setStackScroll(mSv.getStackScroll() + deltaY); + int curStackScroll = mSv.getStackScroll(); + if (mSv.isScrollOutOfBounds(curStackScroll + deltaY)) { + // Scale the touch if we are overscrolling + deltaY /= Constants.Values.TaskStackView.TouchOverscrollScaleFactor; + } + mSv.setStackScroll(curStackScroll + deltaY); if (mSv.isScrollOutOfBounds()) { mVelocityTracker.clear(); } |