summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Brabham <optedoblivion@cyngn.com>2015-04-13 12:56:07 -0700
committerMatt Garnes <matt@cyngn.com>2015-04-28 00:25:48 +0000
commitf533ad90223718f9b5f6d35adc180618620313a6 (patch)
tree818bbca91faed12630afb8a16b1b5d17aa309bea
parent3d6a266a83ad078df67acccf2d33610f993a34a3 (diff)
downloadandroid_packages_apps_Trebuchet-f533ad90223718f9b5f6d35adc180618620313a6.tar.gz
android_packages_apps_Trebuchet-f533ad90223718f9b5f6d35adc180618620313a6.tar.bz2
android_packages_apps_Trebuchet-f533ad90223718f9b5f6d35adc180618620313a6.zip
Clean up scrolling
- Eliminate creation of garbage - Square up interface - Post animation signals to handler so they can be cancelled and redispatched with new data for the updated signal. Change-Id: I9824b7eb762a8d565e22e118bf3f07a8a4791ce8 (cherry picked from commit 22c34f768d1cf58f7b340350ef0a64b2c1ae9485)
-rw-r--r--res/layout/app_drawer_container.xml2
-rw-r--r--res/layout/app_drawer_item.xml2
-rw-r--r--res/values/colors.xml1
-rw-r--r--res/values/dimens.xml8
-rw-r--r--src/com/android/launcher3/AppDrawerListAdapter.java77
-rw-r--r--src/com/android/launcher3/AppDrawerScrubber.java249
6 files changed, 282 insertions, 57 deletions
diff --git a/res/layout/app_drawer_container.xml b/res/layout/app_drawer_container.xml
index 30a4ceeb0..146906637 100644
--- a/res/layout/app_drawer_container.xml
+++ b/res/layout/app_drawer_container.xml
@@ -82,4 +82,4 @@
android:visibility="invisible"
android:layout_height="100dp" />
</RelativeLayout>
-</FrameLayout> \ No newline at end of file
+</FrameLayout>
diff --git a/res/layout/app_drawer_item.xml b/res/layout/app_drawer_item.xml
index 5d3b94655..46a965226 100644
--- a/res/layout/app_drawer_item.xml
+++ b/res/layout/app_drawer_item.xml
@@ -54,7 +54,7 @@
android:layout_marginTop="10dp"
android:layout_marginLeft="6dp"
android:layout_centerVertical="true"
- android:includeFontPadding="false"
+ android:includeFontPadding="true"
android:gravity="center"
android:singleLine="true"
autofit:minTextSize="8sp"
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 082489d53..7f2f07ad7 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -56,4 +56,5 @@
<color name="app_scrubber_gray_color">@android:color/darker_gray</color>
<color name="scrubber_background">#CC14191E</color>
+ <color name="aftv_shadowColor">#b0000000</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5394ea761..124bcb7db 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -126,4 +126,12 @@
<dimen name="vertical_app_drawer_icon_padding">5dp</dimen>
<dimen name="app_drawer_scrubber_padding">20dp</dimen>
+
+ <!-- App Drawer Item -->
+ <dimen name="container_paddingStart">6dp</dimen>
+ <dimen name="container_paddingEnd">6dp</dimen>
+ <dimen name="aftv_width">32dp</dimen>
+ <dimen name="aftv_marginTop">10dp</dimen>
+ <dimen name="aftv_minTextSize">8sp</dimen>
+ <dimen name="aftv_textSize">24sp</dimen>
</resources>
diff --git a/src/com/android/launcher3/AppDrawerListAdapter.java b/src/com/android/launcher3/AppDrawerListAdapter.java
index 21c1b28e9..25c6bb793 100644
--- a/src/com/android/launcher3/AppDrawerListAdapter.java
+++ b/src/com/android/launcher3/AppDrawerListAdapter.java
@@ -24,14 +24,16 @@ import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.provider.Settings;
+import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.support.v7.widget.RecyclerView;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.SectionIndexer;
import com.android.launcher3.locale.LocaleSetManager;
@@ -51,6 +53,7 @@ import java.util.List;
public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdapter.ViewHolder>
implements View.OnLongClickListener, DragSource, SectionIndexer {
+ private static final String TAG = AppDrawerListAdapter.class.getSimpleName();
private static final String NUMERIC_OR_SPECIAL_HEADER = "#";
/**
@@ -110,14 +113,17 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
public static class ViewHolder extends RecyclerView.ViewHolder {
public AutoFitTextView mTextView;
public ViewGroup mLayout;
- public View mFadingBackgroundFront;
- public View mFadingBackgroundBack;
+ public View mContainerView;
+ public View mFadingBackgroundBackView;
+ public View mFadingBackgroundFrontView;
public ViewHolder(View itemView) {
super(itemView);
+ mContainerView = itemView;
+ mFadingBackgroundBackView = itemView.findViewById(R.id.fading_background_back);
+ mFadingBackgroundFrontView = itemView.findViewById(R.id.fading_background_front);
mTextView = (AutoFitTextView) itemView.findViewById(R.id.drawer_item_title);
+ mTextView.bringToFront();
mLayout = (ViewGroup) itemView.findViewById(R.id.drawer_item_flow);
- mFadingBackgroundFront = itemView.findViewById(R.id.fading_background_front);
- mFadingBackgroundBack = itemView.findViewById(R.id.fading_background_back);
}
}
@@ -158,6 +164,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
mViewHolderSet = new HashSet<>();
mInterpolator = new DecelerateInterpolator();
YDPI = ctx.getResources().getDisplayMetrics().ydpi;
+
mLayoutChangeListener = new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -288,19 +295,22 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
percentage = 1 - percentage;
}
+ // Scale header text letters
final float targetScale = (MAX_SCALE - MIN_SCALE) * percentage + MIN_SCALE;
holder.mTextView.setScaleX(targetScale);
holder.mTextView.setScaleY(targetScale);
+ // Perform animation
if (getSectionForPosition(holder.getPosition()) == mSectionTarget) {
- holder.mFadingBackgroundFront.setVisibility(View.INVISIBLE);
- holder.mFadingBackgroundBack.setAlpha(percentage);
- holder.mFadingBackgroundBack.setVisibility(View.VISIBLE);
+ holder.mFadingBackgroundFrontView.setVisibility(View.INVISIBLE);
+ holder.mFadingBackgroundBackView.setAlpha(percentage);
+ holder.mFadingBackgroundBackView.setVisibility(View.VISIBLE);
} else {
- holder.mFadingBackgroundFront.setAlpha(percentage);
- holder.mFadingBackgroundFront.setVisibility(View.VISIBLE);
- holder.mFadingBackgroundBack.setVisibility(View.INVISIBLE);
+ holder.mFadingBackgroundBackView.setVisibility(View.INVISIBLE);
+ holder.mFadingBackgroundFrontView.setAlpha(percentage);
+ holder.mFadingBackgroundFrontView.setVisibility(View.VISIBLE);
}
+
}
/**
@@ -314,7 +324,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
}
}
- private static class ItemAnimator implements ValueAnimator.AnimatorUpdateListener {
+ private class ItemAnimator implements ValueAnimator.AnimatorUpdateListener {
private ViewHolder mViewHolder;
private ItemAnimatorSet mAnimatorSet;
@@ -325,7 +335,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- mAnimatorSet.animate(mViewHolder, animation);
+ mItemAnimatorSet.animate(mViewHolder, animation);
}
}
@@ -365,9 +375,25 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
private void initParams() {
mDeviceProfile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
- int width = mDeviceProfile.cellWidthPx + 2 * mDeviceProfile.edgeMarginPx;
+ int width = mDeviceProfile.allAppsIconSizePx + 2 * mDeviceProfile.edgeMarginPx;
+ int drawnWidth = (mDeviceProfile.allAppsCellWidthPx * mDeviceProfile.numColumnsBase) +
+ ((mDeviceProfile.edgeMarginPx * 2) * mDeviceProfile.numColumnsBase);
+
mIconParams = new
LinearLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ boolean isLarge = SettingsProvider.getBoolean(mLauncher,
+ SettingsProvider.SETTINGS_UI_GENERAL_ICONS_LARGE,
+ R.bool.preferences_interface_general_icons_large_default);
+
+ if (!isLarge) {
+ mIconParams.setMarginStart(mDeviceProfile.edgeMarginPx);
+ mIconParams.setMarginEnd(mDeviceProfile.edgeMarginPx);
+ }
+
+ mIconParams.topMargin = mDeviceProfile.edgeMarginPx;
+ mIconParams.bottomMargin = mDeviceProfile.edgeMarginPx;
+ mIconParams.gravity = Gravity.CENTER;
mIconRect = new Rect(0, 0, mDeviceProfile.allAppsIconSizePx,
mDeviceProfile.allAppsIconSizePx);
@@ -470,6 +496,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
ArrayList<AppInfo> infos = getAllApps();
mLauncher.mAppDrawer.getLayoutManager().removeAllViews();
+
setApps(infos);
}
@@ -662,6 +689,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
holder.mTextView.setPivotY(holder.mTextView.getHeight() / 2);
final int size = indexedInfo.mInfo.size();
+
for (int i = 0; i < holder.mLayout.getChildCount(); i++) {
AppDrawerIconView icon = (AppDrawerIconView) holder.mLayout.getChildAt(i);
icon.setLayoutParams(mIconParams);
@@ -816,7 +844,26 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
@Override
public int getSectionForPosition(int position) {
- return mSectionHeaders.get(mHeaderList.get(position).mStartString).mSectionIndex;
+ if (mSectionHeaders == null) {
+ return 0;
+ }
+
+ position = (position < 0) ? 0 : position;
+ position = (position > mHeaderList.size()) ? mHeaderList.size() : position;
+
+ int index = 0;
+ AppItemIndexedInfo info = mHeaderList.get(position);
+ if (info != null) {
+ SectionIndices indices = mSectionHeaders.get(info.mStartString);
+ if (indices != null) {
+ index = indices.mSectionIndex;
+ } else {
+ Log.w(TAG, "SectionIndices are null");
+ }
+ } else {
+ Log.w(TAG, "AppItemIndexedInfo is null");
+ }
+ return index;
}
private void filterProtectedApps(ArrayList<AppInfo> list) {
diff --git a/src/com/android/launcher3/AppDrawerScrubber.java b/src/com/android/launcher3/AppDrawerScrubber.java
index b69530d47..de63955b4 100644
--- a/src/com/android/launcher3/AppDrawerScrubber.java
+++ b/src/com/android/launcher3/AppDrawerScrubber.java
@@ -23,6 +23,8 @@ import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;
@@ -34,8 +36,18 @@ import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
+import java.lang.IllegalArgumentException;
import java.util.ArrayList;
+/**
+ * AppDrawerScrubber
+ * <pre>
+ * This is the scrubber at the bottom of the app drawer layout for navigating the application
+ * list
+ * </pre>
+ *
+ * @see {@link android.widget.LinearLayout}
+ */
public class AppDrawerScrubber extends LinearLayout {
private AppDrawerListAdapter mAdapter;
private RecyclerView mListView;
@@ -45,18 +57,198 @@ public class AppDrawerScrubber extends LinearLayout {
private SectionContainer mSectionContainer;
private LinearLayoutManager mLayoutManager;
private ScrubberAnimationState mScrubberAnimationState;
+ private Drawable mTransparentDrawable;
+ private AppDrawerSmoothScroller mLinearSmoothScroller;
+
+ private static final int MSG_SET_TARGET = 1000;
+ private static final int MSG_SMOOTH_SCROLL = MSG_SET_TARGET + 1;
+ private static final int MSG_ANIMATE_PICK = MSG_SMOOTH_SCROLL + 1;
+
+ /**
+ * UiHandler
+ * <pre>
+ * Using a handler for sending signals to perform certain actions. The reason for
+ * using this is to be able to remove and replace a signal if signals are being
+ * sent too fast (e.g. user scrubbing like crazy). This allows the touch loop to
+ * complete then later run the animations in their own loops.
+ * </pre>
+ */
+ private class UiHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_TARGET:
+ int adapterIndex = msg.arg1;
+ performSetTarget(adapterIndex);
+ break;
+ case MSG_ANIMATE_PICK:
+ int index = msg.arg1;
+ int width = msg.arg2;
+ int lastIndex = (Integer)msg.obj;
+ performAnimatePickMessage(index, width, lastIndex);
+ break;
+ case MSG_SMOOTH_SCROLL:
+ int itemDiff = msg.arg1;
+ int itemIndex = msg.arg2;
+ performSmoothScroll(itemDiff, itemIndex);
+ break;
+ default:
+ super.handleMessage(msg);
+ }
+ }
+
+ /**
+ * Overidden to remove identical calls if they are called subsequently fast enough.
+ *
+ * This is the final point that is public in the call chain. Other calls to sendMessageXXX
+ * will eventually call this function which calls "enqueueMessage" which is private.
+ *
+ * @param msg {@link android.os.Message}
+ * @param uptimeMillis {@link java.lang.Long}
+ *
+ * @throws IllegalArgumentException {@link java.lang.IllegalArgumentException}
+ */
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) throws
+ IllegalArgumentException {
+ if (msg == null) {
+ throw new IllegalArgumentException("'msg' cannot be null!");
+ }
+ if (hasMessages(msg.what)) {
+ removeMessages(msg.what);
+ }
+ return super.sendMessageAtTime(msg, uptimeMillis);
+ }
+
+ }
+ private Handler mUiHandler = new UiHandler();
+ private void sendSetTargetMessage(int adapterIndex) {
+ Message msg = mUiHandler.obtainMessage(MSG_SET_TARGET);
+ msg.what = MSG_SET_TARGET;
+ msg.arg1 = adapterIndex;
+ mUiHandler.sendMessage(msg);
+ }
+ private void performSetTarget(int adapterIndex) {
+ if (mAdapter != null) {
+ mAdapter.setSectionTarget(adapterIndex);
+ }
+ }
+ private void sendAnimatePickMessage(int index, int width, int lastIndex) {
+ Message msg = mUiHandler.obtainMessage(MSG_ANIMATE_PICK);
+ msg.what = MSG_ANIMATE_PICK;
+ msg.arg1 = index;
+ msg.arg2 = width;
+ msg.obj = lastIndex;
+ mUiHandler.sendMessage(msg);
+ }
+ private void performAnimatePickMessage(int index, int width, int lastIndex) {
+ if (mScrubberIndicator != null) {
+ // get the index based on the direction the user is scrolling
+ int directionalIndex = mSectionContainer.getDirectionalIndex(lastIndex, index);
+ String sectionText = mSectionContainer.getHeader(directionalIndex);
+ float translateX = (index * width) / (float) mSectionContainer.size();
+ // if we are showing letters, grab the position based on the text view
+ if (mSectionContainer.showLetters()) {
+ translateX = mScrubberText.getPositionOfSection(index);
+ }
+ // center the x position
+ translateX -= mScrubberIndicator.getMeasuredWidth() / 2;
+ mScrubberIndicator.setTranslationX(translateX);
+ mScrubberIndicator.setText(sectionText);
+ }
+ }
+ private void sendSmoothScrollMessage(int itemDiff, int itemIndex) {
+ Message msg = mUiHandler.obtainMessage(MSG_SMOOTH_SCROLL);
+ msg.what = MSG_SMOOTH_SCROLL;
+ msg.arg1 = itemDiff;
+ msg.arg2 = itemIndex;
+ mUiHandler.sendMessage(msg);
+ }
+ private void performSmoothScroll(int itemDiff, int itemIndex) {
+ if (mLinearSmoothScroller == null) {
+ mLinearSmoothScroller = new AppDrawerSmoothScroller(mContext);
+ }
+ mLinearSmoothScroller.setItemDiff(itemDiff);
+ mLinearSmoothScroller.setTargetPosition(itemIndex);
+ mLayoutManager.startSmoothScroll(mLinearSmoothScroller);
+ }
+ /**
+ * Constructor
+ *
+ * @param context {@link android.content.Context}
+ * @param attrs {@link android.util.AttributeSet}
+ */
public AppDrawerScrubber(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
+ /**
+ * Constructor
+ *
+ * @param context {@link android.content.Context}
+ */
public AppDrawerScrubber(Context context) {
super(context);
init(context);
}
/**
+ * AppDrawerSmoothScroller
+ * <pre>
+ * This is a smooth scroller with the ability to set an item diff
+ * </pre>
+ *
+ * @see {@link android.support.v7.widget.LinearSmoothScroller}
+ */
+ private class AppDrawerSmoothScroller extends LinearSmoothScroller {
+
+ // Members
+ private int mItemDiff = 0;
+
+ public AppDrawerSmoothScroller(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected int getVerticalSnapPreference() {
+ // position the item against the end of the list view
+ return SNAP_TO_END;
+ }
+
+ @Override
+ public PointF computeScrollVectorForPosition(int targetPosition) {
+ return mLayoutManager.computeScrollVectorForPosition(targetPosition);
+ }
+
+ @Override
+ public int calculateDyToMakeVisible(View view, int snapPreference) {
+ int dy = super.calculateDyToMakeVisible(view, snapPreference);
+ return dy - mItemDiff;
+ }
+
+ /**
+ * Set the item difference
+ *
+ * @param itemDiff
+ */
+ public void setItemDiff(int itemDiff) {
+ mItemDiff = itemDiff;
+ }
+
+ /**
+ * Get the item difference
+ *
+ * @return {@link java.lang.Integer}
+ */
+ public int getItemDiff() {
+ return mItemDiff;
+ }
+
+ }
+
+ /**
* Simple container class that tries to abstract out the knowledge of complex sections vs
* simple string sections
*/
@@ -131,7 +323,7 @@ public class AppDrawerScrubber extends LinearLayout {
mSeekBar.setMax(mSectionContainer.size() - 1);
// show a white line if there are no letters, otherwise show transparent
- Drawable d = mSectionContainer.showLetters() ? new ColorDrawable(Color.TRANSPARENT)
+ Drawable d = mSectionContainer.showLetters() ? mTransparentDrawable
: getContext().getResources().getDrawable(R.drawable.seek_back);
((ViewGroup)mSeekBar.getParent()).setBackground(d);
@@ -155,6 +347,7 @@ public class AppDrawerScrubber extends LinearLayout {
private void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.scrub_layout, this);
+ mTransparentDrawable = new ColorDrawable(Color.TRANSPARENT);
mScrubberAnimationState = new ScrubberAnimationState();
mSeekBar = (SeekBar) findViewById(R.id.scrubber);
mScrubberText = (AutoExpandTextView) findViewById(R.id.scrubberText);
@@ -193,6 +386,9 @@ public class AppDrawerScrubber extends LinearLayout {
}
private void animateIn() {
+ if (mScrubberIndicator == null) {
+ return;
+ }
// start from a scratch position when animating in
mScrubberIndicator.animate().cancel();
mScrubberIndicator.setPivotX(mScrubberIndicator.getMeasuredWidth() / 2);
@@ -218,11 +414,13 @@ public class AppDrawerScrubber extends LinearLayout {
animateOut();
}
}
- })
- .start();
+ }).start();
}
private void animateOut() {
+ if (mScrubberIndicator == null) {
+ return;
+ }
mScrubberIndicator.animate()
.alpha(SCRUBBER_ALPHA_START)
.scaleX(SCRUBBER_SCALE_START)
@@ -242,24 +440,12 @@ public class AppDrawerScrubber extends LinearLayout {
if (!isReady()) {
return;
}
+ progressChanged(seekBar, index, fromUser);
+ }
- if (mScrubberIndicator != null) {
- // get the index based on the direction the user is scrolling
- int directionalIndex = mSectionContainer.getDirectionalIndex(mLastIndex, index);
- String sectionText = mSectionContainer.getHeader(directionalIndex);
-
- float translateX = (index * seekBar.getWidth()) / (float)mSectionContainer.size();
- // if we are showing letters, grab the position based on the text view
- if (mSectionContainer.showLetters()) {
- translateX = mScrubberText.getPositionOfSection(index);
- }
-
- // center the x position
- translateX -= mScrubberIndicator.getMeasuredWidth() / 2;
+ private void progressChanged(SeekBar seekBar, int index, boolean fromUser) {
- mScrubberIndicator.setTranslationX(translateX);
- mScrubberIndicator.setText(sectionText);
- }
+ sendAnimatePickMessage(index, seekBar.getWidth(), mLastIndex);
// get the index of the underlying list
int adapterIndex = mSectionContainer.getAdapterIndex(mLastIndex, index);
@@ -272,32 +458,15 @@ public class AppDrawerScrubber extends LinearLayout {
itemHeight = child.getMeasuredHeight();
}
+ // Start smooth scroll from this Looper loop
if (itemHeight != 0) {
// scroll to the item such that there are 2 rows beneath it from the bottom
final int itemDiff = 2 * itemHeight;
- LinearSmoothScroller scroller = new LinearSmoothScroller(mListView.getContext()) {
- @Override
- protected int getVerticalSnapPreference() {
- // position the item against the end of the list view
- return SNAP_TO_END;
- }
-
- @Override
- public PointF computeScrollVectorForPosition(int targetPosition) {
- return mLayoutManager.computeScrollVectorForPosition(targetPosition);
- }
-
- @Override
- public int calculateDyToMakeVisible(View view, int snapPreference) {
- int dy = super.calculateDyToMakeVisible(view, snapPreference);
- return dy - itemDiff;
- }
- };
- scroller.setTargetPosition(itemIndex);
- mLayoutManager.startSmoothScroll(scroller);
+ sendSmoothScrollMessage(itemDiff, itemIndex);
}
- mAdapter.setSectionTarget(adapterIndex);
+ // Post set target index on queue to get processed by Looper later
+ sendSetTargetMessage(adapterIndex);
mLastIndex = index;
}