Loading res/layout/apps_empty_view.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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" Loading res/values-sw600dp/dimens.xml +3 −3 Original line number Diff line number Diff line Loading @@ -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 --> Loading res/values-sw720dp/dimens.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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 --> Loading src/com/android/launcher3/AlphabeticalAppsList.java +83 −18 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 */ Loading Loading @@ -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 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; } } // The maximum number of rows allowed in a merged section before we stop merging private static final int MAX_ROWS_IN_MERGED_SECTION = 3; 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<>(); Loading @@ -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); Loading @@ -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(); } Loading Loading @@ -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)) { Loading Loading @@ -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); Loading @@ -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++; } } } Loading src/com/android/launcher3/AppsContainerView.java +12 −4 Original line number Diff line number Diff line Loading @@ -213,8 +213,14 @@ public class AppsContainerView extends BaseContainerView implements DragSource, new AppsContainerSearchEditTextView.OnBackKeyListener() { @Override public void onBackKey() { // 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); } } }); } } Loading Loading @@ -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 Loading Loading
res/layout/apps_empty_view.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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" Loading
res/values-sw600dp/dimens.xml +3 −3 Original line number Diff line number Diff line Loading @@ -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 --> Loading
res/values-sw720dp/dimens.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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 --> Loading
src/com/android/launcher3/AlphabeticalAppsList.java +83 −18 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 */ Loading Loading @@ -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 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; } } // The maximum number of rows allowed in a merged section before we stop merging private static final int MAX_ROWS_IN_MERGED_SECTION = 3; 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<>(); Loading @@ -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); Loading @@ -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(); } Loading Loading @@ -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)) { Loading Loading @@ -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); Loading @@ -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++; } } } Loading
src/com/android/launcher3/AppsContainerView.java +12 −4 Original line number Diff line number Diff line Loading @@ -213,8 +213,14 @@ public class AppsContainerView extends BaseContainerView implements DragSource, new AppsContainerSearchEditTextView.OnBackKeyListener() { @Override public void onBackKey() { // 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); } } }); } } Loading Loading @@ -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 Loading