diff options
-rw-r--r-- | res/layout/apps_empty_view.xml | 2 | ||||
-rw-r--r-- | res/values-sw600dp/dimens.xml | 6 | ||||
-rw-r--r-- | res/values-sw720dp/dimens.xml | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/AlphabeticalAppsList.java | 101 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsContainerView.java | 16 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsGridAdapter.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher3/BaseContainerView.java | 5 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 9 | ||||
-rw-r--r-- | src/com/android/launcher3/widget/WidgetsContainerView.java | 2 |
9 files changed, 115 insertions, 36 deletions
diff --git a/res/layout/apps_empty_view.xml b/res/layout/apps_empty_view.xml index 8408077a2..e4c4e2e8c 100644 --- a/res/layout/apps_empty_view.xml +++ b/res/layout/apps_empty_view.xml @@ -18,7 +18,7 @@ android:id="@+id/empty_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center" + android:gravity="center" android:paddingTop="24dp" android:paddingBottom="24dp" android:paddingRight="@dimen/apps_grid_view_start_margin" diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml index b18464292..2bdd4f0fe 100644 --- a/res/values-sw600dp/dimens.xml +++ b/res/values-sw600dp/dimens.xml @@ -18,10 +18,10 @@ <dimen name="app_icon_size">64dp</dimen> <!-- Apps view --> - <dimen name="apps_container_inset">24dp</dimen> - <dimen name="apps_grid_view_start_margin">64dp</dimen> + <dimen name="apps_container_inset">18dp</dimen> + <dimen name="apps_grid_view_start_margin">0dp</dimen> <dimen name="apps_view_section_text_size">26sp</dimen> - <dimen name="apps_view_row_height">76dp</dimen> + <dimen name="apps_view_row_height">72dp</dimen> <dimen name="apps_icon_top_bottom_padding">12dp</dimen> <!-- AppsCustomize --> diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml index cec6b7db0..39b0c8006 100644 --- a/res/values-sw720dp/dimens.xml +++ b/res/values-sw720dp/dimens.xml @@ -16,7 +16,7 @@ <resources> <dimen name="app_icon_size">72dp</dimen> - <dimen name="apps_search_bar_height">56dp</dimen> + <dimen name="apps_search_bar_height">54dp</dimen> <dimen name="apps_icon_top_bottom_padding">16dp</dimen> <!-- QSB --> diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java index 62cb237e1..de4edcb7b 100644 --- a/src/com/android/launcher3/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/AlphabeticalAppsList.java @@ -3,6 +3,7 @@ package com.android.launcher3; import android.content.ComponentName; import android.content.Context; import android.support.v7.widget.RecyclerView; +import android.util.Log; import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; @@ -77,6 +78,9 @@ class AppNameComparator { */ public class AlphabeticalAppsList { + public static final String TAG = "AlphabeticalAppsList"; + private static final boolean DEBUG = false; + /** * Info about a section in the alphabetic list */ @@ -162,11 +166,58 @@ public class AlphabeticalAppsList { * A filter interface to limit the set of applications in the apps list. */ public interface Filter { - public boolean retainApp(AppInfo info, String sectionName); + boolean retainApp(AppInfo info, String sectionName); + } + + /** + * Common interface for different merging strategies. + */ + private interface MergeAlgorithm { + boolean continueMerging(int sectionAppCount, int numAppsPerRow, int mergeCount); } - // The maximum number of rows allowed in a merged section before we stop merging - private static final int MAX_ROWS_IN_MERGED_SECTION = 3; + /** + * The logic we use to merge sections on tablets. + */ + private static class TabletMergeAlgorithm implements MergeAlgorithm { + + @Override + public boolean continueMerging(int sectionAppCount, int numAppsPerRow, int mergeCount) { + // Merge EVERYTHING + return true; + } + } + + /** + * The logic we use to merge sections on phones. + */ + private static class PhoneMergeAlgorithm implements MergeAlgorithm { + + private int mMinAppsPerRow; + private int mMinRowsInMergedSection; + private int mMaxAllowableMerges; + + public PhoneMergeAlgorithm(int minAppsPerRow, int minRowsInMergedSection, int maxNumMerges) { + mMinAppsPerRow = minAppsPerRow; + mMinRowsInMergedSection = minRowsInMergedSection; + mMaxAllowableMerges = maxNumMerges; + } + + @Override + public boolean continueMerging(int sectionAppCount, int numAppsPerRow, int mergeCount) { + // Continue merging if the number of hanging apps on the final row is less than some + // fixed number (ragged), the merged rows has yet to exceed some minimum row count, + // and while the number of merged sections is less than some fixed number of merges + int rows = sectionAppCount / numAppsPerRow; + int cols = sectionAppCount % numAppsPerRow; + return (0 < cols && cols < mMinAppsPerRow) && + rows < mMinRowsInMergedSection && + mergeCount < mMaxAllowableMerges; + } + } + + private static final int MIN_ROWS_IN_MERGED_SECTION_PHONE = 3; + private static final int MAX_NUM_MERGES_PHONE = 2; private List<AppInfo> mApps = new ArrayList<>(); private List<AppInfo> mFilteredApps = new ArrayList<>(); @@ -174,13 +225,13 @@ public class AlphabeticalAppsList { private List<SectionInfo> mSections = new ArrayList<>(); private List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>(); private List<ComponentName> mPredictedApps = new ArrayList<>(); + private HashMap<CharSequence, String> mCachedSectionNames = new HashMap<>(); private RecyclerView.Adapter mAdapter; private Filter mFilter; private AlphabeticIndexCompat mIndexer; private AppNameComparator mAppNameComparator; + private MergeAlgorithm mMergeAlgorithm; private int mNumAppsPerRow; - // The maximum number of section merges we allow at a given time before we stop merging - private int mMaxAllowableMerges = Integer.MAX_VALUE; public AlphabeticalAppsList(Context context, int numAppsPerRow) { mIndexer = new AlphabeticIndexCompat(context); @@ -193,7 +244,16 @@ public class AlphabeticalAppsList { */ public void setNumAppsPerRow(int numAppsPerRow) { mNumAppsPerRow = numAppsPerRow; - mMaxAllowableMerges = (int) Math.ceil(numAppsPerRow / 2f); + + // Update the merge algorithm + DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + if (grid.isPhone()) { + mMergeAlgorithm = new PhoneMergeAlgorithm((int) Math.ceil(numAppsPerRow / 2f), + MIN_ROWS_IN_MERGED_SECTION_PHONE, MAX_NUM_MERGES_PHONE); + } else { + mMergeAlgorithm = new TabletMergeAlgorithm(); + } + onAppsUpdated(); } @@ -392,7 +452,15 @@ public class AlphabeticalAppsList { for (int i = 0; i < numApps; i++) { boolean isPredictedApp = i < numPredictedApps; AppInfo info = allApps.get(i); - String sectionName = isPredictedApp ? "" : mIndexer.computeSectionName(info.title); + String sectionName = ""; + if (!isPredictedApp) { + // Only cache section names from non-predicted apps + sectionName = mCachedSectionNames.get(info.title); + if (sectionName == null) { + sectionName = mIndexer.computeSectionName(info.title); + mCachedSectionNames.put(info.title, sectionName); + } + } // Check if we want to retain this app if (mFilter != null && !mFilter.retainApp(info, sectionName)) { @@ -429,20 +497,14 @@ public class AlphabeticalAppsList { // Go through each section and try and merge some of the sections if (AppsContainerView.GRID_MERGE_SECTIONS && !hasFilter()) { - int minNumAppsPerRow = (int) Math.ceil(mNumAppsPerRow / 2f); int sectionAppCount = 0; for (int i = 0; i < mSections.size(); i++) { SectionInfo section = mSections.get(i); sectionAppCount = section.numApps; int mergeCount = 1; - // Merge rows if the last app in this section is in a column that is greater than - // 0, but less than the min number of apps per row. In addition, apply the - // constraint to stop merging if the number of rows in the section is greater than - // some limit, and also if there are no lessons to merge. - while (0 < (sectionAppCount % mNumAppsPerRow) && - (sectionAppCount % mNumAppsPerRow) < minNumAppsPerRow && - (sectionAppCount / mNumAppsPerRow) < MAX_ROWS_IN_MERGED_SECTION && + // Merge rows based on the current strategy + while (mMergeAlgorithm.continueMerging(sectionAppCount, mNumAppsPerRow, mergeCount) && (i + 1) < mSections.size()) { SectionInfo nextSection = mSections.remove(i + 1); @@ -465,10 +527,13 @@ public class AlphabeticalAppsList { } section.numApps += nextSection.numApps; sectionAppCount += nextSection.numApps; - mergeCount++; - if (mergeCount >= mMaxAllowableMerges) { - break; + + if (DEBUG) { + Log.d(TAG, "Merging: " + nextSection.firstAppItem.sectionName + + " to " + section.firstAppItem.sectionName + + " mergedNumRows: " + (sectionAppCount / mNumAppsPerRow)); } + mergeCount++; } } } diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java index b8d30d081..8a5c6605e 100644 --- a/src/com/android/launcher3/AppsContainerView.java +++ b/src/com/android/launcher3/AppsContainerView.java @@ -213,7 +213,13 @@ public class AppsContainerView extends BaseContainerView implements DragSource, new AppsContainerSearchEditTextView.OnBackKeyListener() { @Override public void onBackKey() { - hideSearchField(true, true); + // Only hide the search field if there is no query, or if there + // are no filtered results + String query = Utilities.trim( + mSearchBarEditView.getEditableText().toString()); + if (query.isEmpty() || mApps.hasNoFilteredResults()) { + hideSearchField(true, true); + } } }); } @@ -277,15 +283,17 @@ public class AppsContainerView extends BaseContainerView implements DragSource, } else { // If there are fixed bounds, then we update the padding to reflect the fixed bounds. setPadding(mFixedBounds.left, mFixedBounds.top, getMeasuredWidth() - mFixedBounds.right, - mInsets.bottom); + mFixedBounds.bottom); } // Update the apps recycler view, inset it by the container inset as well + DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + int startMargin = grid.isPhone() ? mContentMarginStart : 0; int inset = mFixedBounds.isEmpty() ? mContainerInset : mFixedBoundsContainerInset; if (isRtl) { - mAppsRecyclerView.setPadding(inset, inset, inset + mContentMarginStart, inset); + mAppsRecyclerView.setPadding(inset, inset, inset + startMargin, inset); } else { - mAppsRecyclerView.setPadding(inset + mContentMarginStart, inset, inset, inset); + mAppsRecyclerView.setPadding(inset + startMargin, inset, inset, inset); } // Update the header bar diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java index 9ecb2eeb6..563044916 100644 --- a/src/com/android/launcher3/AppsGridAdapter.java +++ b/src/com/android/launcher3/AppsGridAdapter.java @@ -90,6 +90,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { return; } + DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); boolean hasDrawnPredictedAppDivider = false; int childCount = parent.getChildCount(); @@ -104,8 +105,6 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { if (shouldDrawItemDivider(holder, items) && !hasDrawnPredictedAppDivider) { // Draw the divider under the predicted app - DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid(). - getDeviceProfile(); int top = child.getTop() + child.getHeight(); int left = parent.getPaddingLeft(); int right = parent.getWidth() - parent.getPaddingRight(); @@ -113,7 +112,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { c.drawLine(left + iconInset, top, right - iconInset, top, mPredictedAppsDividerPaint); hasDrawnPredictedAppDivider = true; - } else if (shouldDrawItemSection(holder, i, items)) { + } else if (grid.isPhone() && shouldDrawItemSection(holder, i, items)) { // At this point, we only draw sections for each section break; int viewTopOffset = (2 * child.getPaddingTop()); int pos = holder.getPosition(); @@ -132,7 +131,8 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { continue; } - // Find the section code points + + // Find the section name bounds PointF sectionBounds = getAndCacheSectionBounds(sectionName); // Calculate where to draw the section diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java index 2a8443221..bd1c625e3 100644 --- a/src/com/android/launcher3/BaseContainerView.java +++ b/src/com/android/launcher3/BaseContainerView.java @@ -59,11 +59,12 @@ public class BaseContainerView extends FrameLayout implements Insettable { mFixedBounds.set(fixedBounds); if (Launcher.DISABLE_ALL_APPS_SEARCH_INTEGRATION) { mFixedBounds.top = mInsets.top; - mFixedBounds.bottom = getMeasuredHeight(); + mFixedBounds.bottom = mInsets.bottom; } // To ensure that the child RecyclerView has the full width to handle touches right to // the edge of the screen, we only apply the top and bottom padding to the bounds - mFixedBounds.inset(0, mFixedBoundsContainerInset); + mFixedBounds.top += mFixedBoundsContainerInset; + mFixedBounds.bottom += mFixedBoundsContainerInset; onFixedBoundsUpdated(); } // Post the updates since they can trigger a relayout, and this call can be triggered from diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 16e4ce644..a289fce87 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -350,6 +350,9 @@ public class Launcher extends Activity private DeviceProfile mDeviceProfile; + // This is set to the view that launched the activity that navigated the user away from + // launcher. Since there is no callback for when the activity has finished launching, enable + // the press state and keep this reference to reset the press state when we return to launcher. private BubbleTextView mWaitingForResume; protected static HashMap<String, CustomAppWidget> sCustomAppWidgets = @@ -1021,10 +1024,12 @@ public class Launcher extends Activity if (mOnResumeState == State.WORKSPACE) { showWorkspace(false); } else if (mOnResumeState == State.APPS) { + boolean launchedFromApp = (mWaitingForResume != null); // Don't update the predicted apps if the user is returning to launcher in the apps - // view as they may be depending on the UI to be static to switch to another app + // view after launching an app, as they may be depending on the UI to be static to + // switch to another app, otherwise, if it was showAppsView(false /* animated */, false /* resetListToTop */, - false /* updatePredictedApps */); + !launchedFromApp /* updatePredictedApps */); } else if (mOnResumeState == State.WIDGETS) { showWidgetsView(false, false); } diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index 439227f52..f8d7d9256 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -373,7 +373,7 @@ public class WidgetsContainerView extends BaseContainerView } else { // If there are fixed bounds, then we update the padding to reflect the fixed bounds. setPadding(mFixedBounds.left, mFixedBounds.top, getMeasuredWidth() - mFixedBounds.right, - mInsets.bottom); + mFixedBounds.bottom); } } |