diff options
author | Nebojsa Cvetkovic <nebkat@gmail.com> | 2013-12-15 19:46:56 +0000 |
---|---|---|
committer | Danesh M <daneshm90@gmail.com> | 2014-01-24 16:25:19 -0800 |
commit | 7fc14e45774e3094ef3afdf391a13ad54df62a3e (patch) | |
tree | a50303eadf4dab290f99ef0a3c52446da2271827 | |
parent | 04d59a5a3bda757080acf34a974474317e7a6ab3 (diff) | |
download | packages_apps_Trebuchet-7fc14e45774e3094ef3afdf391a13ad54df62a3e.tar.gz packages_apps_Trebuchet-7fc14e45774e3094ef3afdf391a13ad54df62a3e.tar.bz2 packages_apps_Trebuchet-7fc14e45774e3094ef3afdf391a13ad54df62a3e.zip |
AppsCustomize: Overview panel
Change-Id: I5cfd1183194ee15d8bb18dcd2536a644c9599978
-rw-r--r-- | res/layout-land/launcher.xml | 8 | ||||
-rw-r--r-- | res/layout-port/launcher.xml | 8 | ||||
-rw-r--r-- | res/layout-sw720dp/launcher.xml | 8 | ||||
-rw-r--r-- | res/layout/overview_panel.xml | 22 | ||||
-rw-r--r-- | res/menu/apps_customize_sort_mode.xml | 11 | ||||
-rw-r--r-- | res/values/cm_strings.xml | 9 | ||||
-rw-r--r-- | res/xml/preferences_general.xml | 4 | ||||
-rw-r--r-- | res/xml/preferences_headers.xml | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/AppFilter.java | 1 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsCustomizeLayout.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsCustomizePagedView.java | 451 | ||||
-rw-r--r-- | src/com/android/launcher3/DynamicGrid.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 112 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherModel.java | 23 | ||||
-rw-r--r-- | src/com/android/launcher3/Workspace.java | 2 |
15 files changed, 629 insertions, 46 deletions
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml index 77ea2e9aa..3666b5986 100644 --- a/res/layout-land/launcher.xml +++ b/res/layout-land/launcher.xml @@ -50,10 +50,6 @@ android:id="@+id/qsb_bar" layout="@layout/qsb_bar" /> - <include layout="@layout/overview_panel" - android:id="@+id/overview_panel" - android:visibility="gone" /> - <!-- The Workspace cling must appear under the AppsCustomizePagedView below to ensure that it is still visible during the transition to AllApps and doesn't overlay on top of that view. --> @@ -97,5 +93,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" /> + + <include layout="@layout/overview_panel" + android:id="@+id/overview_panel" + android:visibility="gone" /> </com.android.launcher3.DragLayer> </FrameLayout> diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml index 6fbf7c717..11f74ba1d 100644 --- a/res/layout-port/launcher.xml +++ b/res/layout-port/launcher.xml @@ -44,10 +44,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - <include layout="@layout/overview_panel" - android:id="@+id/overview_panel" - android:visibility="gone" /> - <!-- Keep these behind the workspace so that they are not visible when we go into AllApps --> <include @@ -102,5 +98,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" /> + + <include layout="@layout/overview_panel" + android:id="@+id/overview_panel" + android:visibility="gone" /> </com.android.launcher3.DragLayer> </FrameLayout> diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml index 951e63a39..4f6aaf503 100644 --- a/res/layout-sw720dp/launcher.xml +++ b/res/layout-sw720dp/launcher.xml @@ -49,10 +49,6 @@ android:id="@+id/qsb_bar" layout="@layout/qsb_bar" /> - <include layout="@layout/overview_panel" - android:id="@+id/overview_panel" - android:visibility="gone" /> - <!-- Keep these behind the workspace so that they are not visible when we go into AllApps --> <include @@ -97,5 +93,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" /> + + <include layout="@layout/overview_panel" + android:id="@+id/overview_panel" + android:visibility="gone" /> </com.android.launcher3.DragLayer> </FrameLayout> diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml index 46e6e07e2..ada2b2483 100644 --- a/res/layout/overview_panel.xml +++ b/res/layout/overview_panel.xml @@ -50,6 +50,17 @@ android:fontFamily="sans-serif-condensed" android:textAllCaps="true" android:textSize="12sp" /> + <TextView + android:id="@+id/sort_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/sort_button_text" + android:drawablePadding="4dp" + android:drawableTop="@drawable/wallpaper_button" + android:gravity="center_horizontal" + android:fontFamily="sans-serif-condensed" + android:textAllCaps="true" + android:textSize="12sp" /> <Space android:layout_width="@dimen/overview_panel_buttonSpacing" android:layout_height="wrap_content"/> @@ -64,6 +75,17 @@ android:fontFamily="sans-serif-condensed" android:textAllCaps="true" android:textSize="12sp"/> + <TextView + android:id="@+id/filter_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/filter_button_text" + android:drawablePadding="4dp" + android:gravity="center_horizontal" + android:drawableTop="@drawable/widget_button" + android:fontFamily="sans-serif-condensed" + android:textAllCaps="true" + android:textSize="12sp"/> <Space android:layout_width="@dimen/overview_panel_buttonSpacing" android:layout_height="wrap_content"/> diff --git a/res/menu/apps_customize_sort_mode.xml b/res/menu/apps_customize_sort_mode.xml new file mode 100644 index 000000000..cb5f8faff --- /dev/null +++ b/res/menu/apps_customize_sort_mode.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <group android:checkableBehavior="single"> + <item android:id="@+id/sort_mode_title" + android:title="@string/sort_mode_title" /> + <item android:id="@+id/sort_mode_launch_count" + android:title="@string/sort_mode_launch_count" /> + <item android:id="@+id/sort_mode_install_time" + android:title="@string/sort_mode_install_time" /> + </group> +</menu>
\ No newline at end of file diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index eb0db0dbc..05cb477dd 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -5,9 +5,18 @@ <!-- App version --> <string name="application_version" translatable="false">1.0</string> + <!-- Strings for the customization mode --> + <!-- Text for sorting mode button --> + <string name="sort_button_text">Sort</string> + <!-- Text for filter button --> + <string name="filter_button_text">Filter</string> <!-- Text for default screen button --> <string name="default_screen_button_text">Default Screen</string> + <string name="sort_mode_title">Title</string> + <string name="sort_mode_launch_count">Launch Count</string> + <string name="sort_mode_install_time">Install Time</string> + <!-- Settings --> <string name="preferences_title">Settings</string> <!-- UI --> diff --git a/res/xml/preferences_general.xml b/res/xml/preferences_general.xml index 24010b361..58e8a9aea 100644 --- a/res/xml/preferences_general.xml +++ b/res/xml/preferences_general.xml @@ -15,11 +15,11 @@ --> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res/com.cyanogenmod.trebuchet" + xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher3" android:key="ui_general" android:title="@string/preferences_interface_general_title"> <CheckBoxPreference android:key="ui_general_large_icons" android:title="@string/preferences_interface_general_large_icons_title" android:summary="@string/preferences_interface_general_large_icons_summary" android:defaultValue="@bool/preferences_interface_general_large_icons_default" /> -</PreferenceScreen>
\ No newline at end of file +</PreferenceScreen> diff --git a/res/xml/preferences_headers.xml b/res/xml/preferences_headers.xml index 303532e8f..367ef832a 100644 --- a/res/xml/preferences_headers.xml +++ b/res/xml/preferences_headers.xml @@ -28,7 +28,7 @@ android:title="@string/preferences_interface_dock_title" /> <header android:id="@+id/preferences_general_section" - android:fragment="org.cyanogenmod.trebuchet.settings.SettingsActivity$GeneralFragment" + android:fragment="com.android.launcher3.settings.SettingsActivity$GeneralFragment" android:title="@string/preferences_interface_general_title" /> <header android:id="@+id/preferences_application_section" diff --git a/src/com/android/launcher3/AppFilter.java b/src/com/android/launcher3/AppFilter.java index e01436d7a..81556856e 100644 --- a/src/com/android/launcher3/AppFilter.java +++ b/src/com/android/launcher3/AppFilter.java @@ -31,5 +31,4 @@ public abstract class AppFilter { return null; } } - } diff --git a/src/com/android/launcher3/AppsCustomizeLayout.java b/src/com/android/launcher3/AppsCustomizeLayout.java index f811006ea..ea1c36a9c 100644 --- a/src/com/android/launcher3/AppsCustomizeLayout.java +++ b/src/com/android/launcher3/AppsCustomizeLayout.java @@ -28,6 +28,7 @@ import android.widget.FrameLayout; public class AppsCustomizeLayout extends FrameLayout implements LauncherTransitionable, Insettable { + private AppsCustomizePagedView mAppsCustomizePane; private FrameLayout mContent; @@ -65,6 +66,13 @@ public class AppsCustomizeLayout extends FrameLayout implements LauncherTransiti mAppsCustomizePane = appsCustomizePane; mContent = (FrameLayout) findViewById(R.id.apps_customize_content); if (mAppsCustomizePane == null) throw new Resources.NotFoundException(); + + findViewById(R.id.page_indicator).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mAppsCustomizePane.enterOverviewMode(); + } + }); } public boolean onInterceptTouchEvent(MotionEvent ev) { diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java index ace83f77e..34dd9294d 100644 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ b/src/com/android/launcher3/AppsCustomizePagedView.java @@ -16,7 +16,10 @@ package com.android.launcher3; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; @@ -36,13 +39,16 @@ import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Process; +import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.GridLayout; @@ -53,6 +59,7 @@ import com.android.launcher3.DropTarget.DragObject; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; @@ -157,6 +164,16 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } private ContentType mContentType = ContentType.Applications; + /** + * The different sort modes than can be used to order items. + */ + public enum SortMode { + Title, + LaunchCount, + InstallTime + } + private SortMode mSortMode = SortMode.Title; + // Refs private Launcher mLauncher; private DragController mDragController; @@ -188,12 +205,33 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private int mNumAppsPages; private int mNumWidgetPages; + // Animation states + enum State { NORMAL, OVERVIEW}; + private State mState = State.NORMAL; + private boolean mIsSwitchingState = false; + + // Animation values + private float mNewScale; + private float[] mOldBackgroundAlphas; + private float[] mOldTranslationXs; + private float[] mOldTranslationYs; + private float[] mOldScaleXs; + private float[] mOldScaleYs; + private float[] mOldAlphas; + private float[] mNewBackgroundAlphas; + private float[] mNewTranslationXs; + private float[] mNewTranslationYs; + private float[] mNewScaleXs; + private float[] mNewScaleYs; + private float[] mNewAlphas; + // Relating to the scroll and overscroll effects Workspace.ZInterpolator mZInterpolator = new Workspace.ZInterpolator(0.5f); private static float CAMERA_DISTANCE = 6500; private static float TRANSITION_SCALE_FACTOR = 0.74f; private static float TRANSITION_PIVOT = 0.65f; private static float TRANSITION_MAX_ROTATION = 22; + private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f; private static final boolean PERFORM_OVERSCROLL_ROTATION = true; private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f); private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4); @@ -226,6 +264,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private Rect mTmpRect = new Rect(); + private float mOverviewModeShrinkFactor; + private int mOverviewModePageOffset; + // Used for drawing shortcut previews BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache(); PaintCache mCachedShortcutPreviewPaint = new PaintCache(); @@ -242,6 +283,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private boolean mInBulkBind; private boolean mNeedToUpdatePageCountsAndInvalidateData; + private static boolean sAccessibilityEnabled; + public AppsCustomizePagedView(Context context, AttributeSet attrs) { super(context, attrs); mLayoutInflater = LayoutInflater.from(context); @@ -282,6 +325,11 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen Context context = getContext(); Resources r = context.getResources(); setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f); + mOverviewModeShrinkFactor = + r.getInteger(R.integer.config_workspaceOverviewShrinkPercentage) / 100.0f; + mOverviewModePageOffset = r.getDimensionPixelSize(R.dimen.overview_mode_page_offset); + + setMinScale(mOverviewModeShrinkFactor - 0.2f); } public void onFinishInflate() { @@ -527,10 +575,22 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } + /** + * Called directly from a CellLayout (not by the framework), after we've been added as a + * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout + * that it should intercept touch events, which is not something that is normally supported. + */ + @Override + public boolean onTouch(View v, MotionEvent event) { + return isInOverviewMode() || mIsSwitchingState; + } + public boolean onKey(View v, int keyCode, KeyEvent event) { return FocusHelper.handleAppsCustomizeKeyEvent(v, keyCode, event); } + private final Workspace.ZoomInInterpolator mZoomInInterpolator = new Workspace.ZoomInInterpolator(); + /* * PagedViewWithDraggableItems implementation */ @@ -903,6 +963,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen cancelAllTasks(); } + protected void onResume() { + AccessibilityManager am = (AccessibilityManager) + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + sAccessibilityEnabled = am.isEnabled(); + } + public void clearAllWidgetPages() { cancelAllTasks(); int count = getChildCount(); @@ -976,6 +1042,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private void setupPage(AppsCustomizeCellLayout layout) { layout.setGridSize(mCellCountX, mCellCountY); + layout.setOnClickListener(mLauncher); + // Note: We force a measure here to get around the fact that when we do layout calculations // immediately after syncing, we don't have a proper width. That said, we already know the // expected page width, so we can actually optimize by hiding all the TextView-based @@ -988,6 +1056,18 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen setVisibilityOnChildren(layout, View.VISIBLE); } + @Override + public void onChildViewAdded(View parent, View child) { + // For overview mode + if (child instanceof CellLayout) { + CellLayout cl = ((CellLayout) child); + cl.setOnInterceptTouchListener(this); + cl.setClickable(true); + cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO); + } + super.onChildViewAdded(parent, child); + } + public void syncAppsPageItems(int page, boolean immediate) { // ensure that we have the right number of items on the pages final boolean isRtl = isLayoutRtl(); @@ -1354,6 +1434,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen final boolean isRtl = isLayoutRtl(); super.screenScrolled(screenCenter); + enableHwLayersOnVisiblePages(); + + if (isInOverviewMode()) { + return; + } + for (int i = 0; i < getChildCount(); i++) { View v = getPageAt(i); if (v != null) { @@ -1419,7 +1505,11 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen v.setTranslationX(translationX); v.setScaleX(scale); v.setScaleY(scale); - v.setAlpha(alpha); + if (v instanceof CellLayout) { + ((CellLayout) v).getShortcutsAndWidgets().setAlpha(alpha); + } else { + v.setAlpha(alpha); + } // If the view has 0 alpha, we set it to be invisible so as to prevent // it from accepting touches @@ -1430,8 +1520,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } } - - enableHwLayersOnVisiblePages(); } private void enableHwLayersOnVisiblePages() { @@ -1456,26 +1544,316 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen for (int i = 0; i < screenCount; i++) { final View layout = (View) getPageAt(i); - if (!(leftScreen <= i && i <= rightScreen && - (i == forceDrawScreen || shouldDrawChild(layout)))) { + boolean enableLayer = leftScreen <= i && i <= rightScreen && + (i == forceDrawScreen || shouldDrawChild(layout)); + if (layout instanceof CellLayout) { + ((CellLayout) layout).enableHardwareLayer(enableLayer); + } else if (enableLayer) { + if (layout.getLayerType() != LAYER_TYPE_HARDWARE) { + layout.setLayerType(LAYER_TYPE_HARDWARE, null); + } + } else { layout.setLayerType(LAYER_TYPE_NONE, null); } } + } - for (int i = 0; i < screenCount; i++) { - final View layout = (View) getPageAt(i); + protected void overScroll(float amount) { + acceleratedOverScroll(amount); + } - if (leftScreen <= i && i <= rightScreen && - (i == forceDrawScreen || shouldDrawChild(layout))) { - if (layout.getLayerType() != LAYER_TYPE_HARDWARE) { - layout.setLayerType(LAYER_TYPE_HARDWARE, null); + public boolean isInOverviewMode() { + return mState == State.OVERVIEW; + } + + public boolean enterOverviewMode() { + if (mTouchState != TOUCH_STATE_REST || !mIsDataReady || mContentType != ContentType.Applications) { + return false; + } + enableOverviewMode(true, -1, true); + return true; + } + + public void exitOverviewMode(boolean animated) { + exitOverviewMode(-1, animated); + } + + public void exitOverviewMode(int snapPage, boolean animated) { + enableOverviewMode(false, snapPage, animated); + } + + private void enableOverviewMode(boolean enable, int snapPage, boolean animated) { + State finalState = AppsCustomizePagedView.State.OVERVIEW; + if (!enable) { + finalState = AppsCustomizePagedView.State.NORMAL; + } + + mLauncher.updateOverviewPanel(); + + Animator appsCustomizeAnim = getChangeStateAnimation(finalState, animated, 0, snapPage); + if (appsCustomizeAnim != null) { + onTransitionPrepare(); + appsCustomizeAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator arg0) { + onTransitionEnd(); + } + }); + appsCustomizeAnim.start(); + } + } + + int getOverviewModeTranslationY() { + int childHeight = getNormalChildHeight(); + int viewPortHeight = getViewportHeight(); + int scaledChildHeight = (int) (mOverviewModeShrinkFactor * childHeight); + + int offset = (viewPortHeight - scaledChildHeight) / 2; + int offsetDelta = mOverviewModePageOffset - offset + mInsets.top; + + return offsetDelta; + } + + private void setState(State state) { + mState = state; + updateAccessibilityFlags(); + } + + private void updateAccessibilityFlags() { + int accessible = mState == State.NORMAL ? + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES : + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; + setImportantForAccessibility(accessible); + } + + private void initAnimationArrays() { + final int childCount = getChildCount(); + if (mOldBackgroundAlphas != null) return; + mOldBackgroundAlphas = new float[childCount]; + mOldTranslationXs = new float[childCount]; + mOldTranslationYs = new float[childCount]; + mOldScaleXs = new float[childCount]; + mOldScaleYs = new float[childCount]; + mOldAlphas = new float[childCount]; + mNewBackgroundAlphas = new float[childCount]; + mNewTranslationXs = new float[childCount]; + mNewTranslationYs = new float[childCount]; + mNewScaleXs = new float[childCount]; + mNewScaleYs = new float[childCount]; + mNewAlphas = new float[childCount]; + } + + Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) { + if (mState == state) { + return null; + } + + // Initialize animation arrays for the first time if necessary + initAnimationArrays(); + + AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null; + + final State oldState = mState; + final boolean oldStateIsNormal = (oldState == State.NORMAL); + final boolean oldStateIsOverview = (oldState == State.OVERVIEW); + setState(state); + final boolean stateIsNormal = (state == State.NORMAL); + final boolean stateIsOverview = (state == State.OVERVIEW); + float finalBackgroundAlpha = stateIsOverview ? 1.0f : 0f; + float finalPageIndicatorAlpha = stateIsOverview ? 0f : 1f; + float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f; + float finalWorkspaceTranslationY = stateIsOverview ? getOverviewModeTranslationY() : 0; + + boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview); + boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal); + + mNewScale = 1.0f; + + if (state != State.NORMAL) { + if (stateIsOverview) { + mNewScale = mOverviewModeShrinkFactor; + } + } + + final int duration = getResources().getInteger(R.integer.config_overviewTransitionTime); + + for (int i = 0; i < getChildCount(); i++) { + final CellLayout cl = (CellLayout) getChildAt(i); + float translationX = 0f; + float translationY = 0f; + float scaleX = 1f; + float scaleY = 1f; + float finalAlpha = 1f; + + if (stateIsOverview) { + cl.setVisibility(VISIBLE); + cl.setTranslationX(0f); + cl.setScaleX(1f); + cl.setScaleY(1f); + cl.setShortcutAndWidgetAlpha(1f); + } + + mOldAlphas[i] = cl.getShortcutsAndWidgets().getAlpha(); + mNewAlphas[i] = finalAlpha; + if (animated) { + mOldBackgroundAlphas[i] = cl.getBackgroundAlpha(); + mOldTranslationXs[i] = cl.getTranslationX(); + mOldTranslationYs[i] = cl.getTranslationY(); + mOldScaleXs[i] = cl.getScaleX(); + mNewScaleXs[i] = cl.getScaleY(); + + mNewBackgroundAlphas[i] = finalBackgroundAlpha; + mNewTranslationXs[i] = translationX; + mNewTranslationYs[i] = translationY; + mNewScaleXs[i] = scaleX; + mNewScaleYs[i] = scaleY; + } else { + cl.setBackgroundAlpha(finalBackgroundAlpha); + cl.setTranslationX(translationX); + cl.setTranslationY(translationY); + cl.setScaleX(scaleX); + cl.setScaleY(scaleY); + cl.setShortcutAndWidgetAlpha(finalAlpha); + } + } + + final View overviewPanel = mLauncher.getOverviewPanel(); + if (animated) { + anim.setDuration(duration); + LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this); + scale.scaleX(mNewScale) + .scaleY(mNewScale) + .translationY(finalWorkspaceTranslationY) + .setInterpolator(mZoomInInterpolator); + anim.play(scale); + ValueAnimator invalidate = ValueAnimator.ofFloat(0f, 1f); + invalidate.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + invalidate(); + } + }); + anim.play(invalidate); + ObjectAnimator pageIndicatorAlpha = null; + if (getPageIndicator() != null) { + pageIndicatorAlpha = ObjectAnimator.ofFloat(getPageIndicator(), "alpha", + finalPageIndicatorAlpha); + } + ObjectAnimator overviewPanelAlpha = ObjectAnimator.ofFloat(overviewPanel, + "alpha", finalOverviewPanelAlpha); + + overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel)); + + if (overviewToWorkspace) { + overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2)); + } + + if (getPageIndicator() != null) { + pageIndicatorAlpha.addListener(new AlphaUpdateListener(getPageIndicator())); + } + + anim.play(overviewPanelAlpha); + anim.play(pageIndicatorAlpha); + + for (int index = 0; index < getChildCount(); index++) { + final int i = index; + + final CellLayout cl = (CellLayout) getChildAt(i); + if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) { + cl.setBackgroundAlpha(mNewBackgroundAlphas[i]); + cl.setTranslationX(mNewTranslationXs[i]); + cl.setTranslationY(mNewTranslationYs[i]); + cl.setScaleX(mNewScaleXs[i]); + cl.setScaleY(mNewScaleYs[i]); + cl.getShortcutsAndWidgets().setAlpha(mNewAlphas[i]); + } else { + LauncherViewPropertyAnimator a = new LauncherViewPropertyAnimator(cl); + a.translationX(mNewTranslationXs[i]) + .translationY(mNewTranslationYs[i]) + .scaleX(mNewScaleXs[i]) + .scaleY(mNewScaleYs[i]) + .setDuration(duration) + .setInterpolator(mZoomInInterpolator); + anim.play(a); + a = new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets()); + a.translationX(mNewTranslationXs[i]) + .alpha(mNewAlphas[i]) + .setDuration(duration) + .setInterpolator(mZoomInInterpolator); + anim.play(a); + if (mOldBackgroundAlphas[i] != 0 || + mNewBackgroundAlphas[i] != 0) { + ValueAnimator bgAnim = + LauncherAnimUtils.ofFloat(cl, 0f, 1f); + bgAnim.setInterpolator(mZoomInInterpolator); + bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() { + public void onAnimationUpdate(float a, float b) { + cl.setBackgroundAlpha( + a * mOldBackgroundAlphas[i] + + b * mNewBackgroundAlphas[i]); + } + }); + anim.play(bgAnim); + } } } + + anim.setStartDelay(delay); + } else { + overviewPanel.setAlpha(finalOverviewPanelAlpha); + AlphaUpdateListener.updateVisibility(overviewPanel); + if (getPageIndicator() != null) { + getPageIndicator().setAlpha(finalPageIndicatorAlpha); + AlphaUpdateListener.updateVisibility(getPageIndicator()); + } + setScaleX(mNewScale); + setScaleY(mNewScale); + setTranslationY(finalWorkspaceTranslationY); } + return anim; } - protected void overScroll(float amount) { - acceleratedOverScroll(amount); + static class AlphaUpdateListener implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener { + View view; + public AlphaUpdateListener(View v) { + view = v; + } + + @Override + public void onAnimationUpdate(ValueAnimator arg0) { + updateVisibility(view); + } + + public static void updateVisibility(View view) { + // We want to avoid the extra layout pass by setting the views to GONE unless + // accessibility is on, in which case not setting them to GONE causes a glitch. + int invisibleState = sAccessibilityEnabled ? GONE : INVISIBLE; + if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) { + view.setVisibility(invisibleState); + } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD + && view.getVisibility() != VISIBLE) { + view.setVisibility(VISIBLE); + } + } + + @Override + public void onAnimationCancel(Animator arg0) { + } + + @Override + public void onAnimationEnd(Animator arg0) { + updateVisibility(view); + } + + @Override + public void onAnimationRepeat(Animator arg0) { + } + + @Override + public void onAnimationStart(Animator arg0) { + // We want the views to be visible for animation, so fade-in/out is visible + view.setVisibility(VISIBLE); + } } /** @@ -1495,6 +1873,49 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mSaveInstanceStateItemIndex = -1; } + private void onTransitionPrepare() { + mIsSwitchingState = true; + + // Invalidate here to ensure that the pages are rendered during the state change transition. + invalidate(); + + enableHwLayersOnVisiblePages(); + } + + private void onTransitionEnd() { + mIsSwitchingState = false; + } + + public Comparator<AppInfo> getComparatorForSortMode() { + switch (mSortMode) { + case Title: + return LauncherModel.getAppNameComparator(); + case LaunchCount: + return LauncherModel.getAppLaunchCountComparator(mLauncher.getStats()); + case InstallTime: + return LauncherModel.getAppInstallTimeComparator(); + } + return LauncherModel.getAppNameComparator(); + } + + public void setSortMode(SortMode sortMode) { + if (mSortMode == sortMode) return; + + mSortMode = sortMode; + + Collections.sort(mApps, getComparatorForSortMode()); + + if (mContentType == ContentType.Applications) { + for (int i = 0; i < getChildCount(); i++) { + syncAppsPageItems(i, true); + } + } + } + + public SortMode getSortMode() { + return mSortMode; + } + /* * AllAppsView implementation */ @@ -1523,7 +1944,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen public void setApps(ArrayList<AppInfo> list) { if (!DISABLE_ALL_APPS) { mApps = list; - Collections.sort(mApps, LauncherModel.getAppNameComparator()); + Collections.sort(mApps, getComparatorForSortMode()); updatePageCountsAndInvalidateData(); } } @@ -1532,7 +1953,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int count = list.size(); for (int i = 0; i < count; ++i) { AppInfo info = list.get(i); - int index = Collections.binarySearch(mApps, info, LauncherModel.getAppNameComparator()); + int index = Collections.binarySearch(mApps, info, getComparatorForSortMode()); if (index < 0) { mApps.add(-(index + 1), info); } diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java index 5bbb9214f..c6f2cb282 100644 --- a/src/com/android/launcher3/DynamicGrid.java +++ b/src/com/android/launcher3/DynamicGrid.java @@ -480,6 +480,12 @@ class DeviceProfile { pageIndicator.setLayoutParams(lp); } } + + // Layout the apps customize + View appsCustomize = launcher.findViewById(R.id.apps_customize_pane_content); + lp = (FrameLayout.LayoutParams) appsCustomize.getLayoutParams(); + lp.gravity = Gravity.CENTER; + appsCustomize.setLayoutParams(lp); } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 3d3b8b0d0..53fa329fb 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -76,6 +76,7 @@ import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuItem; import android.view.MotionEvent; import android.view.Surface; import android.view.View; @@ -90,9 +91,11 @@ import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodManager; + import android.widget.Advanceable; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; @@ -916,6 +919,7 @@ public class Launcher extends Activity } mWorkspace.updateInteractionForState(); mWorkspace.onResume(); + mAppsCustomizeContent.onResume(); } @Override @@ -984,7 +988,44 @@ public class Launcher extends Activity startActivity(settings); if (mWorkspace.isInOverviewMode()) { mWorkspace.exitOverviewMode(false); + } else if (mAppsCustomizeContent.isInOverviewMode()) { + mAppsCustomizeContent.exitOverviewMode(false); + } + } + + public void onClickSortModeButton(View v) { + final PopupMenu popupMenu = new PopupMenu(this, v); + final Menu menu = popupMenu.getMenu(); + popupMenu.inflate(R.menu.apps_customize_sort_mode); + AppsCustomizePagedView.SortMode sortMode = mAppsCustomizeContent.getSortMode(); + switch (sortMode) { + case Title: + menu.findItem(R.id.sort_mode_title).setChecked(true); + break; + case LaunchCount: + menu.findItem(R.id.sort_mode_launch_count).setChecked(true); + break; + case InstallTime: + menu.findItem(R.id.sort_mode_install_time).setChecked(true); + break; } + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.sort_mode_title: + mAppsCustomizeContent.setSortMode(AppsCustomizePagedView.SortMode.Title); + break; + case R.id.sort_mode_install_time: + mAppsCustomizeContent.setSortMode(AppsCustomizePagedView.SortMode.InstallTime); + break; + case R.id.sort_mode_launch_count: + mAppsCustomizeContent.setSortMode(AppsCustomizePagedView.SortMode.LaunchCount); + break; + } + return true; + } + }); + popupMenu.show(); } public interface QSBScroller { @@ -1160,6 +1201,7 @@ public class Launcher extends Activity } mOverviewPanel = findViewById(R.id.overview_panel); + mOverviewPanel.setAlpha(0f); View widgetButton = findViewById(R.id.widget_button); widgetButton.setOnClickListener(new OnClickListener() { @Override @@ -1195,7 +1237,24 @@ public class Launcher extends Activity } }); defaultScreenButton.setOnTouchListener(getHapticFeedbackTouchListener()); - mOverviewPanel.setAlpha(0f); + + View sortButton = findViewById(R.id.sort_button); + sortButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onClickSortModeButton(v); + } + }); + sortButton.setOnTouchListener(getHapticFeedbackTouchListener()); + + View filterButton = findViewById(R.id.filter_button); + filterButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + + } + }); + filterButton.setOnTouchListener(getHapticFeedbackTouchListener()); // Setup the workspace mWorkspace.setHapticFeedbackEnabled(false); @@ -1891,6 +1950,12 @@ public class Launcher extends Activity } else { mWorkspace.exitOverviewMode(true); } + } else { + if (!mAppsCustomizeContent.isInOverviewMode()) { + mAppsCustomizeContent.enterOverviewMode(); + } else { + mAppsCustomizeContent.exitOverviewMode(true); + } } return false; } @@ -2116,11 +2181,15 @@ public class Launcher extends Activity @Override public void onBackPressed() { if (isAllAppsVisible()) { - if (mAppsCustomizeContent.getContentType() == - AppsCustomizePagedView.ContentType.Applications) { - showWorkspace(true); + if (mAppsCustomizeContent.isInOverviewMode()) { + mAppsCustomizeContent.exitOverviewMode(true); } else { - showOverviewMode(true); + if (mAppsCustomizeContent.getContentType() == + AppsCustomizePagedView.ContentType.Applications) { + showWorkspace(true); + } else { + showOverviewMode(true); + } } } else if (mWorkspace.isInOverviewMode()) { mWorkspace.exitOverviewMode(true); @@ -2172,8 +2241,14 @@ public class Launcher extends Activity } if (v instanceof CellLayout) { - if (mWorkspace.isInOverviewMode()) { - mWorkspace.exitOverviewMode(mWorkspace.indexOfChild(v), true); + if (isAllAppsVisible()) { + if (mAppsCustomizeContent.isInOverviewMode()) { + mAppsCustomizeContent.exitOverviewMode(mAppsCustomizeContent.indexOfChild(v), true); + } + } else { + if (mWorkspace.isInOverviewMode()) { + mWorkspace.exitOverviewMode(mWorkspace.indexOfChild(v), true); + } } } @@ -2671,6 +2746,25 @@ public class Launcher extends Activity return mWorkspace; } + public void updateOverviewPanel() { + View defaultScreenButton = mOverviewPanel.findViewById(R.id.default_screen_button); + View widgetButton = mOverviewPanel.findViewById(R.id.widget_button); + View wallpaperButton = mOverviewPanel.findViewById(R.id.wallpaper_button); + View sortButton = mOverviewPanel.findViewById(R.id.sort_button); + View filterButton = mOverviewPanel.findViewById(R.id.filter_button); + + defaultScreenButton.setVisibility(!isAllAppsVisible() ? View.VISIBLE : View.GONE); + widgetButton.setVisibility(!isAllAppsVisible() ? View.VISIBLE : View.GONE); + wallpaperButton.setVisibility(!isAllAppsVisible() ? View.VISIBLE : View.GONE); + sortButton.setVisibility(isAllAppsVisible() ? View.VISIBLE : View.GONE); + // TODO: implement filtering + // filterButton.setVisibility(isAllAppsVisible() ? View.VISIBLE : View.GONE); + filterButton.setVisibility(View.GONE); + + // Make sure overview panel is drawn above apps customize + mOverviewPanel.bringToFront(); + } + public boolean isAllAppsVisible() { return (mState == State.APPS_CUSTOMIZE) || (mOnResumeState == State.APPS_CUSTOMIZE); } @@ -3082,6 +3176,10 @@ public class Launcher extends Activity void showAllApps(boolean animated, AppsCustomizePagedView.ContentType contentType, boolean resetPageToZero) { + if (mAppsCustomizeContent.isInOverviewMode()) { + mAppsCustomizeContent.exitOverviewMode(false); + } + if (mState != State.WORKSPACE) return; if (resetPageToZero) { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 63ec2a257..e26d405bc 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -3094,14 +3094,21 @@ public class LauncherModel extends BroadcastReceiver { } }; } - public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR - = new Comparator<AppInfo>() { - public final int compare(AppInfo a, AppInfo b) { - if (a.firstInstallTime < b.firstInstallTime) return 1; - if (a.firstInstallTime > b.firstInstallTime) return -1; - return 0; - } - }; + public static final Comparator<AppInfo> getAppInstallTimeComparator() { + final Collator collator = Collator.getInstance(); + return new Comparator<AppInfo>() { + public final int compare(AppInfo a, AppInfo b) { + if (a.firstInstallTime < b.firstInstallTime) return 1; + if (a.firstInstallTime > b.firstInstallTime) return -1; + int result = collator.compare(a.title.toString().trim(), + b.title.toString().trim()); + if (result == 0) { + result = a.componentName.compareTo(b.componentName); + } + return result; + } + }; + } public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() { final Collator collator = Collator.getInstance(); return new Comparator<AppWidgetProviderInfo>() { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index a5e2c10a1..12117f451 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1962,6 +1962,8 @@ public class Workspace extends SmoothPagedView finalState = Workspace.State.NORMAL; } + mLauncher.updateOverviewPanel(); + Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage); if (workspaceAnim != null) { onTransitionPrepare(); |