diff options
20 files changed, 277 insertions, 116 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 3af38f384..99a6ad9aa 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -20,7 +20,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.launcher3"> - <uses-sdk android:targetSdkVersion="21" android:minSdkVersion="16"/> + <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="16"/> <permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" diff --git a/WallpaperPicker/res/values-v19/styles.xml b/WallpaperPicker/res/values-v19/styles.xml index 136cf012c..15fb0ea2a 100644 --- a/WallpaperPicker/res/values-v19/styles.xml +++ b/WallpaperPicker/res/values-v19/styles.xml @@ -25,7 +25,7 @@ <item name="android:windowTranslucentNavigation">true</item> </style> - <style name="Theme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar"> + <style name="Theme" parent="@style/BaseWallpaperTheme"> <item name="android:windowTranslucentStatus">true</item> <item name="android:windowTranslucentNavigation">true</item> </style> diff --git a/WallpaperPicker/res/values-v21/styles.xml b/WallpaperPicker/res/values-v21/styles.xml index 582ab8fed..70220edb9 100644 --- a/WallpaperPicker/res/values-v21/styles.xml +++ b/WallpaperPicker/res/values-v21/styles.xml @@ -33,4 +33,11 @@ <item name="android:background">?android:attr/selectableItemBackgroundBorderless</item> </style> + <style name="Theme" parent="@style/BaseWallpaperTheme"> + <item name="android:windowTranslucentStatus">true</item> + <item name="android:windowTranslucentNavigation">true</item> + <item name="android:colorControlActivated">@color/launcher_accent_color</item> + <item name="android:colorAccent">@color/launcher_accent_color</item> + <item name="android:colorPrimary">@color/launcher_accent_color</item> + </style> </resources>
\ No newline at end of file diff --git a/WallpaperPicker/res/values/colors.xml b/WallpaperPicker/res/values/colors.xml index adae7cff6..6ba32f06d 100644 --- a/WallpaperPicker/res/values/colors.xml +++ b/WallpaperPicker/res/values/colors.xml @@ -19,4 +19,6 @@ --> <resources> <color name="wallpaper_picker_translucent_gray">#66000000</color> + + <color name="launcher_accent_color">#ff009688</color> </resources> diff --git a/WallpaperPicker/res/values/styles.xml b/WallpaperPicker/res/values/styles.xml index 74aeab903..d1c945a32 100644 --- a/WallpaperPicker/res/values/styles.xml +++ b/WallpaperPicker/res/values/styles.xml @@ -35,9 +35,15 @@ <item name="android:background">#88000000</item> </style> - <style name="Theme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar"> + <style name="BaseWallpaperTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar"> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:colorBackgroundCacheHint">@null</item> + <item name="android:windowShowWallpaper">true</item> + <item name="android:windowNoTitle">true</item> </style> + <style name="Theme" parent="@style/BaseWallpaperTheme"></style> + <style name="ActionBarSetWallpaperStyle" parent="@android:style/Widget.DeviceDefault.ActionButton"> <item name="android:textColor">#ffffffff</item> <item name="android:background">?android:attr/selectableItemBackground</item> diff --git a/proguard.flags b/proguard.flags index a8e2b6092..e6c4c51c4 100644 --- a/proguard.flags +++ b/proguard.flags @@ -3,10 +3,10 @@ } -keep class com.android.launcher3.BaseRecyclerViewFastScrollBar { - public void setWidth(int); - public int getWidth(); - public void setTrackAlpha(int); - public int getTrackAlpha(); + public void setThumbWidth(int); + public int getThumbWidth(); + public void setTrackWidth(int); + public int getTrackWidth(); } -keep class com.android.launcher3.BaseRecyclerViewFastScrollPopup { diff --git a/res/layout/all_apps_search_market.xml b/res/layout/all_apps_search_market.xml index 1282069c8..1ed508890 100644 --- a/res/layout/all_apps_search_market.xml +++ b/res/layout/all_apps_search_market.xml @@ -23,7 +23,7 @@ android:paddingRight="16dp" android:fontFamily="sans-serif-medium" android:textSize="14sp" - android:textColor="#009688" + android:textColor="@color/launcher_accent_color" android:textAllCaps="true" android:focusable="false" android:background="@drawable/all_apps_search_market_bg" /> diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml index 4b7423eba..1f02dce3c 100644 --- a/res/layout/overview_panel.xml +++ b/res/layout/overview_panel.xml @@ -32,6 +32,7 @@ android:gravity="center_horizontal" android:text="@string/wallpaper_button_text" android:textAllCaps="true" + android:textColor="@android:color/white" android:textSize="12sp" /> <TextView @@ -45,6 +46,7 @@ android:gravity="center_horizontal" android:text="@string/widget_button_text" android:textAllCaps="true" + android:textColor="@android:color/white" android:textSize="12sp" /> <TextView @@ -58,6 +60,7 @@ android:gravity="center_horizontal" android:text="@string/settings_button_text" android:textAllCaps="true" + android:textColor="@android:color/white" android:textSize="12sp" /> </LinearLayout>
\ No newline at end of file diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml index 275840def..252ebf01e 100644 --- a/res/layout/user_folder.xml +++ b/res/layout/user_folder.xml @@ -70,7 +70,6 @@ android:textColor="#ff777777" android:textColorHighlight="#ffCCCCCC" android:textColorHint="#ff808080" - android:textCursorDrawable="@null" android:textSize="14sp" /> <include diff --git a/res/values/colors.xml b/res/values/colors.xml index 0add48cd8..8a7f62743 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -39,7 +39,7 @@ <color name="outline_color">#FFFFFFFF</color> <!-- Containers --> - <color name="container_fastscroll_thumb_inactive_color">#42000000</color> + <color name="container_fastscroll_thumb_inactive_color">#009688</color> <color name="container_fastscroll_thumb_active_color">#009688</color> <!-- All Apps --> @@ -47,7 +47,6 @@ <color name="all_apps_search_market_button_focused_bg_color">#DDDDDD</color> <!-- Widgets view --> - <color name="widgets_view_fastscroll_thumb_inactive_color">#42FFFFFF</color> <color name="widgets_view_section_text_color">#FFFFFF</color> <color name="widgets_view_item_text_color">#C4C4C4</color> <color name="widgets_cell_color">#263238</color> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index b9fb6e257..3f141513f 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -55,9 +55,9 @@ <!-- Notes: container_bounds_inset - quantum_panel_outer_padding --> <dimen name="container_bounds_minus_quantum_panel_padding_inset">4dp</dimen> - <dimen name="container_fastscroll_thumb_min_width">4dp</dimen> - <dimen name="container_fastscroll_thumb_max_width">8dp</dimen> - <dimen name="container_fastscroll_thumb_height">64dp</dimen> + <dimen name="container_fastscroll_thumb_min_width">5dp</dimen> + <dimen name="container_fastscroll_thumb_max_width">9dp</dimen> + <dimen name="container_fastscroll_thumb_height">72dp</dimen> <dimen name="container_fastscroll_thumb_touch_inset">-24dp</dimen> <dimen name="container_fastscroll_popup_size">72dp</dimen> <dimen name="container_fastscroll_popup_text_size">48dp</dimen> diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java index 0fae427e8..f0d8b3b3d 100644 --- a/src/com/android/launcher3/BaseRecyclerView.java +++ b/src/com/android/launcher3/BaseRecyclerView.java @@ -92,9 +92,15 @@ public abstract class BaseRecyclerView extends RecyclerView // TODO(winsonc): If we want to animate the section heads while scrolling, we can // initiate that here if the recycler view scroll state is not // RecyclerView.SCROLL_STATE_IDLE. + + onUpdateScrollbar(dy); } } + public void reset() { + mScrollbar.reattachThumbToScroll(); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -143,7 +149,7 @@ public abstract class BaseRecyclerView extends RecyclerView mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY); break; } - return mScrollbar.isDragging(); + return mScrollbar.isDraggingThumb(); } public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { @@ -185,12 +191,10 @@ public abstract class BaseRecyclerView extends RecyclerView * AvailableScrollHeight = Total height of the all items - last page height * * This assumes that all rows are the same height. - * - * @param yOffset the offset from the top of the recycler view to start tracking. */ - protected int getAvailableScrollHeight(int rowCount, int rowHeight, int yOffset) { + protected int getAvailableScrollHeight(int rowCount, int rowHeight) { int visibleHeight = getHeight() - mBackgroundPadding.top - mBackgroundPadding.bottom; - int scrollHeight = getPaddingTop() + yOffset + rowCount * rowHeight + getPaddingBottom(); + int scrollHeight = getPaddingTop() + rowCount * rowHeight + getPaddingBottom(); int availableScrollHeight = scrollHeight - visibleHeight; return availableScrollHeight; } @@ -222,7 +226,7 @@ public abstract class BaseRecyclerView extends RecyclerView @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); - onUpdateScrollbar(); + onUpdateScrollbar(0); mScrollbar.draw(canvas); } @@ -234,24 +238,21 @@ public abstract class BaseRecyclerView extends RecyclerView * @param scrollPosState the current scroll position * @param rowCount the number of rows, used to calculate the total scroll height (assumes that * all rows are the same height) - * @param yOffset the offset to start tracking in the recycler view (only used for all apps) */ protected void synchronizeScrollBarThumbOffsetToViewScroll(ScrollPositionState scrollPosState, - int rowCount, int yOffset) { - int availableScrollHeight = getAvailableScrollHeight(rowCount, scrollPosState.rowHeight, - yOffset); - int availableScrollBarHeight = getAvailableScrollBarHeight(); - + int rowCount) { // Only show the scrollbar if there is height to be scrolled + int availableScrollBarHeight = getAvailableScrollBarHeight(); + int availableScrollHeight = getAvailableScrollHeight(rowCount, scrollPosState.rowHeight); if (availableScrollHeight <= 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } // Calculate the current scroll position, the scrollY of the recycler view accounts for the // view padding, while the scrollBarY is drawn right up to the background padding (ignoring // padding) - int scrollY = getPaddingTop() + yOffset + + int scrollY = getPaddingTop() + (scrollPosState.rowIndex * scrollPosState.rowHeight) - scrollPosState.rowTopOffset; int scrollBarY = mBackgroundPadding.top + (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight); @@ -261,9 +262,9 @@ public abstract class BaseRecyclerView extends RecyclerView if (Utilities.isRtl(getResources())) { scrollBarX = mBackgroundPadding.left; } else { - scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getWidth(); + scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth(); } - mScrollbar.setScrollbarThumbOffset(scrollBarX, scrollBarY); + mScrollbar.setThumbOffset(scrollBarX, scrollBarY); } /** @@ -276,10 +277,15 @@ public abstract class BaseRecyclerView extends RecyclerView * Updates the bounds for the scrollbar. * <p>Override in each subclass of this base class. */ - public abstract void onUpdateScrollbar(); + public abstract void onUpdateScrollbar(int dy); /** * <p>Override in each subclass of this base class. */ public void onFastScrollCompleted() {} + + /** + * Returns information about the item that the recycler view is currently scrolled to. + */ + protected abstract void getCurScrollState(ScrollPositionState stateOut); }
\ No newline at end of file diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java index 2c4184dc4..f76aed7ad 100644 --- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java +++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java @@ -23,6 +23,7 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.Point; import android.graphics.Rect; import android.view.MotionEvent; @@ -51,14 +52,20 @@ public class BaseRecyclerViewFastScrollBar { private int mThumbActiveColor; @Thunk Point mThumbOffset = new Point(-1, -1); @Thunk Paint mThumbPaint; - private Paint mTrackPaint; private int mThumbMinWidth; private int mThumbMaxWidth; @Thunk int mThumbWidth; @Thunk int mThumbHeight; + private int mThumbCurvature; + private Path mThumbPath = new Path(); + private Paint mTrackPaint; + private int mTrackWidth; + private float mLastTouchY; // The inset is the buffer around which a point will still register as a click on the scrollbar private int mTouchInset; private boolean mIsDragging; + private boolean mIsThumbDetached; + private boolean mCanThumbDetach; // This is the offset from the top of the scrollbar when the user first starts touching. To // prevent jumping, this offset is applied as the user scrolls. @@ -72,51 +79,74 @@ public class BaseRecyclerViewFastScrollBar { mPopup = new BaseRecyclerViewFastScrollPopup(rv, res); mTrackPaint = new Paint(); mTrackPaint.setColor(rv.getFastScrollerTrackColor(Color.BLACK)); - mTrackPaint.setAlpha(0); + mTrackPaint.setAlpha(MAX_TRACK_ALPHA); mThumbInactiveColor = rv.getFastScrollerThumbInactiveColor( res.getColor(R.color.container_fastscroll_thumb_inactive_color)); mThumbActiveColor = res.getColor(R.color.container_fastscroll_thumb_active_color); mThumbPaint = new Paint(); + mThumbPaint.setAntiAlias(true); mThumbPaint.setColor(mThumbInactiveColor); + mThumbPaint.setStyle(Paint.Style.FILL); mThumbWidth = mThumbMinWidth = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_min_width); mThumbMaxWidth = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_max_width); mThumbHeight = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_height); + mThumbCurvature = mThumbMaxWidth - mThumbMinWidth; mTouchInset = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_touch_inset); } - public void setScrollbarThumbOffset(int x, int y) { + public void setDetachThumbOnFastScroll() { + mCanThumbDetach = true; + } + + public void reattachThumbToScroll() { + mIsThumbDetached = false; + } + + public void setThumbOffset(int x, int y) { if (mThumbOffset.x == x && mThumbOffset.y == y) { return; } - mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight()); + mInvalidateRect.set(mThumbOffset.x - mThumbCurvature, mThumbOffset.y, + mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); mThumbOffset.set(x, y); - mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, - mRv.getHeight())); + updateThumbPath(); + mInvalidateRect.union(mThumbOffset.x - mThumbCurvature, mThumbOffset.y, + mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); mRv.invalidate(mInvalidateRect); } - // Setter/getter for the search bar width for animations - public void setWidth(int width) { - mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight()); + public Point getThumbOffset() { + return mThumbOffset; + } + + // Setter/getter for the thumb bar width for animations + public void setThumbWidth(int width) { + mInvalidateRect.set(mThumbOffset.x - mThumbCurvature, mThumbOffset.y, + mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); mThumbWidth = width; - mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, - mRv.getHeight())); + updateThumbPath(); + mInvalidateRect.union(mThumbOffset.x - mThumbCurvature, mThumbOffset.y, + mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); mRv.invalidate(mInvalidateRect); } - public int getWidth() { + public int getThumbWidth() { return mThumbWidth; } - // Setter/getter for the track background alpha for animations - public void setTrackAlpha(int alpha) { - mTrackPaint.setAlpha(alpha); - mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight()); + // Setter/getter for the track bar width for animations + public void setTrackWidth(int width) { + mInvalidateRect.set(mThumbOffset.x - mThumbCurvature, 0, mThumbOffset.x + mThumbWidth, + mRv.getHeight()); + mTrackWidth = width; + updateThumbPath(); + mInvalidateRect.union(mThumbOffset.x - mThumbCurvature, 0, mThumbOffset.x + mThumbWidth, + mRv.getHeight()); mRv.invalidate(mInvalidateRect); } - public int getTrackAlpha() { - return mTrackPaint.getAlpha(); + public int getTrackWidth() { + return mTrackWidth; } public int getThumbHeight() { @@ -127,10 +157,18 @@ public class BaseRecyclerViewFastScrollBar { return mThumbMaxWidth; } - public boolean isDragging() { + public float getLastTouchY() { + return mLastTouchY; + } + + public boolean isDraggingThumb() { return mIsDragging; } + public boolean isThumbDetached() { + return mIsThumbDetached; + } + /** * Handles the touch event and determines whether to show the fast scroller (or updates it if * it is already showing). @@ -152,6 +190,9 @@ public class BaseRecyclerViewFastScrollBar { Math.abs(y - downY) > config.getScaledTouchSlop()) { mRv.getParent().requestDisallowInterceptTouchEvent(true); mIsDragging = true; + if (mCanThumbDetach) { + mIsThumbDetached = true; + } mTouchOffset += (lastY - downY); mPopup.animateVisibility(true); animateScrollbar(true); @@ -166,11 +207,13 @@ public class BaseRecyclerViewFastScrollBar { mPopup.setSectionName(sectionName); mPopup.animateVisibility(!sectionName.isEmpty()); mRv.invalidate(mPopup.updateFastScrollerBounds(mRv, lastY)); + mLastTouchY = boundedY; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mTouchOffset = 0; + mLastTouchY = 0; if (mIsDragging) { mIsDragging = false; mPopup.animateVisibility(false); @@ -189,8 +232,7 @@ public class BaseRecyclerViewFastScrollBar { if (mTrackPaint.getAlpha() > 0) { canvas.drawRect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight(), mTrackPaint); } - canvas.drawRect(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth, - mThumbOffset.y + mThumbHeight, mThumbPaint); + canvas.drawPath(mThumbPath, mThumbPaint); // Draw the popup mPopup.draw(canvas); @@ -203,27 +245,46 @@ public class BaseRecyclerViewFastScrollBar { if (mScrollbarAnimator != null) { mScrollbarAnimator.cancel(); } - ObjectAnimator trackAlphaAnim = ObjectAnimator.ofInt(this, "trackAlpha", - isScrolling ? MAX_TRACK_ALPHA : 0); - ObjectAnimator thumbWidthAnim = ObjectAnimator.ofInt(this, "width", - isScrolling ? mThumbMaxWidth : mThumbMinWidth); - ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), - mThumbPaint.getColor(), isScrolling ? mThumbActiveColor : mThumbInactiveColor); - colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animator) { - mThumbPaint.setColor((Integer) animator.getAnimatedValue()); - mRv.invalidate(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth, - mThumbOffset.y + mThumbHeight); - } - }); + mScrollbarAnimator = new AnimatorSet(); - mScrollbarAnimator.playTogether(trackAlphaAnim, thumbWidthAnim, colorAnimation); + ObjectAnimator trackWidthAnim = ObjectAnimator.ofInt(this, "trackWidth", + isScrolling ? mThumbMaxWidth : mThumbMinWidth); + ObjectAnimator thumbWidthAnim = ObjectAnimator.ofInt(this, "thumbWidth", + isScrolling ? mThumbMaxWidth : mThumbMinWidth); + mScrollbarAnimator.playTogether(trackWidthAnim, thumbWidthAnim); + if (mThumbActiveColor != mThumbInactiveColor) { + ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), + mThumbPaint.getColor(), isScrolling ? mThumbActiveColor : mThumbInactiveColor); + colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + mThumbPaint.setColor((Integer) animator.getAnimatedValue()); + mRv.invalidate(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth, + mThumbOffset.y + mThumbHeight); + } + }); + mScrollbarAnimator.play(colorAnimation); + } mScrollbarAnimator.setDuration(SCROLL_BAR_VIS_DURATION); mScrollbarAnimator.start(); } /** + * Updates the path for the thumb drawable. + */ + private void updateThumbPath() { + mThumbCurvature = mThumbMaxWidth - mThumbWidth; + mThumbPath.reset(); + mThumbPath.moveTo(mThumbOffset.x + mThumbWidth, mThumbOffset.y); // tr + mThumbPath.lineTo(mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); // br + mThumbPath.lineTo(mThumbOffset.x, mThumbOffset.y + mThumbHeight); // bl + mThumbPath.cubicTo(mThumbOffset.x, mThumbOffset.y + mThumbHeight, + mThumbOffset.x - mThumbCurvature, mThumbOffset.y + mThumbHeight / 2, + mThumbOffset.x, mThumbOffset.y); // bl2tl + mThumbPath.close(); + } + + /** * Returns whether the specified points are near the scroll bar bounds. */ private boolean isNearPoint(int x, int y) { diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java index 1efdfb62d..772a334b9 100644 --- a/src/com/android/launcher3/SearchDropTargetBar.java +++ b/src/com/android/launcher3/SearchDropTargetBar.java @@ -186,7 +186,12 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D */ private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha, int duration) { - if (v != null && Float.compare(v.getAlpha(), alpha) != 0) { + if (v == null) { + return; + } + + animator.cancel(); + if (Float.compare(v.getAlpha(), alpha) != 0) { if (duration > 0) { animator.alpha(alpha).withLayer().setDuration(duration).start(); } else { diff --git a/src/com/android/launcher3/StylusEventHelper.java b/src/com/android/launcher3/StylusEventHelper.java index da46e6a54..e03273a6e 100644 --- a/src/com/android/launcher3/StylusEventHelper.java +++ b/src/com/android/launcher3/StylusEventHelper.java @@ -1,8 +1,5 @@ package com.android.launcher3; -import com.android.launcher3.Utilities; - -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -77,8 +74,9 @@ public class StylusEventHelper { * @param event The event to check. * @return Whether a stylus button press occurred. */ - public static boolean isStylusButtonPressed(MotionEvent event) { + private static boolean isStylusButtonPressed(MotionEvent event) { return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS - && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY); + && ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) + == MotionEvent.BUTTON_SECONDARY); } }
\ No newline at end of file diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index e129dc6d3..6d008ab98 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -555,8 +555,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc @Override public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { if (toWorkspace) { - // Reset the search bar after transitioning home + // Reset the search bar and base recycler view after transitioning home mSearchBarController.reset(); + mAppsRecyclerView.reset(); } } diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index 5aa973a15..1cde7bfc0 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -72,6 +72,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr); + mScrollbar.setDetachThumbOnFastScroll(); } /** @@ -168,8 +169,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView } // Map the touch position back to the scroll of the recycler view - getCurScrollState(mScrollPosState, mApps.getAdapterItems()); - int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0); + getCurScrollState(mScrollPosState); + int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight); LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager(); if (mFastScrollMode == FAST_SCROLL_MODE_FREE_SCROLL) { layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction)); @@ -216,24 +217,83 @@ public class AllAppsRecyclerView extends BaseRecyclerView * Updates the bounds for the scrollbar. */ @Override - public void onUpdateScrollbar() { + public void onUpdateScrollbar(int dy) { List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); // Skip early if there are no items or we haven't been measured if (items.isEmpty() || mNumAppsPerRow == 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } // Find the index and height of the first visible row (all rows have the same height) int rowCount = mApps.getNumAppRows(); - getCurScrollState(mScrollPosState, items); + getCurScrollState(mScrollPosState); if (mScrollPosState.rowIndex < 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } - synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0); + // Only show the scrollbar if there is height to be scrolled + int availableScrollBarHeight = getAvailableScrollBarHeight(); + int availableScrollHeight = getAvailableScrollHeight(mApps.getNumAppRows(), mScrollPosState.rowHeight); + if (availableScrollHeight <= 0) { + mScrollbar.setThumbOffset(-1, -1); + return; + } + + // Calculate the current scroll position, the scrollY of the recycler view accounts for the + // view padding, while the scrollBarY is drawn right up to the background padding (ignoring + // padding) + int scrollY = getPaddingTop() + + (mScrollPosState.rowIndex * mScrollPosState.rowHeight) - mScrollPosState.rowTopOffset; + int scrollBarY = mBackgroundPadding.top + + (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight); + + if (mScrollbar.isThumbDetached()) { + int scrollBarX; + if (Utilities.isRtl(getResources())) { + scrollBarX = mBackgroundPadding.left; + } else { + scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth(); + } + + if (mScrollbar.isDraggingThumb()) { + // If the thumb is detached, then just update the thumb to the current + // touch position + mScrollbar.setThumbOffset(scrollBarX, (int) mScrollbar.getLastTouchY()); + } else { + int thumbScrollY = mScrollbar.getThumbOffset().y; + int diffScrollY = scrollBarY - thumbScrollY; + if (diffScrollY * dy > 0f) { + // User is scrolling in the same direction the thumb needs to catch up to the + // current scroll position. We do this by mapping the difference in movement + // from the original scroll bar position to the difference in movement necessary + // in the detached thumb position to ensure that both speed towards the same + // position at either end of the list. + if (dy < 0) { + int offset = (int) ((dy * thumbScrollY) / (float) scrollBarY); + thumbScrollY += Math.max(offset, diffScrollY); + } else { + int offset = (int) ((dy * (availableScrollBarHeight - thumbScrollY)) / + (float) (availableScrollBarHeight - scrollBarY)); + thumbScrollY += Math.min(offset, diffScrollY); + } + thumbScrollY = Math.max(0, Math.min(availableScrollBarHeight, thumbScrollY)); + mScrollbar.setThumbOffset(scrollBarX, thumbScrollY); + if (scrollBarY == thumbScrollY) { + mScrollbar.reattachThumbToScroll(); + } + } else { + // User is scrolling in an opposite direction to the direction that the thumb + // needs to catch up to the scroll position. Do nothing except for updating + // the scroll bar x to match the thumb width. + mScrollbar.setThumbOffset(scrollBarX, thumbScrollY); + } + } + } else { + synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount); + } } /** @@ -285,13 +345,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView /** * Returns the current scroll state of the apps rows. */ - private void getCurScrollState(ScrollPositionState stateOut, - List<AlphabeticalAppsList.AdapterItem> items) { + protected void getCurScrollState(ScrollPositionState stateOut) { stateOut.rowIndex = -1; stateOut.rowTopOffset = -1; stateOut.rowHeight = -1; // Return early if there are no items or we haven't been measured + List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); if (items.isEmpty() || mNumAppsPerRow == 0) { return; } diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 396f75790..dac0df12a 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -43,6 +43,11 @@ public class AlphabeticalAppsList { private static final boolean DEBUG = false; private static final boolean DEBUG_PREDICTIONS = false; + private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_ROWS_FRACTION = 0; + private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS = 1; + + private final int mFastScrollDistributionMode = FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS; + /** * Info about a section in the alphabetic list */ @@ -85,8 +90,6 @@ public class AlphabeticalAppsList { /** Section & App properties */ // The section for this item public SectionInfo sectionInfo; - // The row that this item shows up on - public int rowIndex; /** App-only properties */ // The section name of this app. Note that there can be multiple items with different @@ -94,6 +97,8 @@ public class AlphabeticalAppsList { public String sectionName = null; // The index of this app in the section public int sectionAppIndex = -1; + // The row that this item shows up on + public int rowIndex; // The index of this app in the row public int rowAppIndex; // The associated AppInfo for the app @@ -188,7 +193,6 @@ public class AlphabeticalAppsList { private int mNumAppsPerRow; private int mNumPredictedAppsPerRow; private int mNumAppRowsInAdapter; - private boolean mDisableEmptyText; public AlphabeticalAppsList(Context context) { mLauncher = (Launcher) context; @@ -216,13 +220,6 @@ public class AlphabeticalAppsList { } /** - * Disables the empty text message when there are no search results. - */ - public void disableEmptyText() { - mDisableEmptyText = true; - } - - /** * Returns all the apps. */ public List<AppInfo> getApps() { @@ -523,18 +520,36 @@ public class AlphabeticalAppsList { } mNumAppRowsInAdapter = rowIndex + 1; - // Pre-calculate all the fast scroller fractions based on the number of rows - float rowFraction = 1f / mNumAppRowsInAdapter; - for (FastScrollSectionInfo info : mFastScrollerSections) { - AdapterItem item = info.fastScrollToItem; - if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE && - item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) { - info.touchFraction = 0f; - continue; - } - - float subRowFraction = item.rowAppIndex * (rowFraction / mNumAppsPerRow); - info.touchFraction = item.rowIndex * rowFraction + subRowFraction; + // Pre-calculate all the fast scroller fractions + switch (mFastScrollDistributionMode) { + case FAST_SCROLL_FRACTION_DISTRIBUTE_BY_ROWS_FRACTION: + float rowFraction = 1f / mNumAppRowsInAdapter; + for (FastScrollSectionInfo info : mFastScrollerSections) { + AdapterItem item = info.fastScrollToItem; + if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE && + item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) { + info.touchFraction = 0f; + continue; + } + + float subRowFraction = item.rowAppIndex * (rowFraction / mNumAppsPerRow); + info.touchFraction = item.rowIndex * rowFraction + subRowFraction; + } + break; + case FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS: + float perSectionTouchFraction = 1f / mFastScrollerSections.size(); + float cumulativeTouchFraction = 0f; + for (FastScrollSectionInfo info : mFastScrollerSections) { + AdapterItem item = info.fastScrollToItem; + if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE && + item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) { + info.touchFraction = 0f; + continue; + } + info.touchFraction = cumulativeTouchFraction; + cumulativeTouchFraction += perSectionTouchFraction; + } + break; } } diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java index 4d404db2b..dc3ec3cd8 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatVL.java +++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java @@ -26,6 +26,7 @@ import android.os.Build; import android.os.UserHandle; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.Utilities; import com.android.launcher3.util.LongArrayMap; import java.util.ArrayList; @@ -100,7 +101,9 @@ public class UserManagerCompatVL extends UserManagerCompatV17 { @Override public long getUserCreationTime(UserHandleCompat user) { - // TODO: Use system API once available. + if (Utilities.ATLEAST_MARSHMALLOW) { + return mUserManager.getUserCreationTime(user.getUser()); + } SharedPreferences prefs = mContext.getSharedPreferences( LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user); diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java index 61e63cdb7..3dcb33268 100644 --- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java @@ -64,10 +64,6 @@ public class WidgetsRecyclerView extends BaseRecyclerView { return Color.WHITE; } - public int getFastScrollerThumbInactiveColor(int defaultInactiveThumbColor) { - return getResources().getColor(R.color.widgets_view_fastscroll_thumb_inactive_color); - } - /** * Sets the widget model in this view, used to determine the fast scroll position. */ @@ -102,7 +98,7 @@ public class WidgetsRecyclerView extends BaseRecyclerView { getCurScrollState(mScrollPosState); float pos = rowCount * touchFraction; - int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0); + int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight); LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager()); layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction)); @@ -115,29 +111,29 @@ public class WidgetsRecyclerView extends BaseRecyclerView { * Updates the bounds for the scrollbar. */ @Override - public void onUpdateScrollbar() { + public void onUpdateScrollbar(int dy) { int rowCount = mWidgets.getPackageSize(); // Skip early if, there are no items. if (rowCount == 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } // Skip early if, there no child laid out in the container. getCurScrollState(mScrollPosState); if (mScrollPosState.rowIndex < 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } - synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0); + synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount); } /** * Returns the current scroll state. */ - private void getCurScrollState(ScrollPositionState stateOut) { + protected void getCurScrollState(ScrollPositionState stateOut) { stateOut.rowIndex = -1; stateOut.rowTopOffset = -1; stateOut.rowHeight = -1; |