summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/apps_grid_row_icon_view.xml4
-rw-r--r--res/layout/apps_list_view.xml4
-rw-r--r--res/layout/widget_cell.xml6
-rw-r--r--res/layout/widgets_list_row_view.xml11
-rw-r--r--res/values-sw600dp/dimens.xml1
-rw-r--r--res/values-sw720dp/dimens.xml2
-rw-r--r--res/values/dimens.xml8
-rw-r--r--src/com/android/launcher3/AlphabeticalAppsList.java71
-rw-r--r--src/com/android/launcher3/AppsContainerRecyclerView.java10
-rw-r--r--src/com/android/launcher3/AppsContainerView.java8
-rw-r--r--src/com/android/launcher3/AppsGridAdapter.java76
-rw-r--r--src/com/android/launcher3/DeviceProfile.java27
-rw-r--r--src/com/android/launcher3/DynamicGrid.java22
-rw-r--r--src/com/android/launcher3/FolderPagedView.java12
-rw-r--r--src/com/android/launcher3/Launcher.java40
-rw-r--r--src/com/android/launcher3/LauncherCallbacks.java2
-rw-r--r--src/com/android/launcher3/LauncherExtension.java6
-rw-r--r--src/com/android/launcher3/widget/WidgetCell.java37
-rw-r--r--src/com/android/launcher3/widget/WidgetRowView.java74
-rw-r--r--src/com/android/launcher3/widget/WidgetsListAdapter.java10
20 files changed, 344 insertions, 87 deletions
diff --git a/res/layout/apps_grid_row_icon_view.xml b/res/layout/apps_grid_row_icon_view.xml
index 286deb454..acb3da334 100644
--- a/res/layout/apps_grid_row_icon_view.xml
+++ b/res/layout/apps_grid_row_icon_view.xml
@@ -21,8 +21,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|center_vertical"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
+ android:paddingTop="@dimen/apps_icon_top_bottom_padding"
+ android:paddingBottom="@dimen/apps_icon_top_bottom_padding"
android:focusable="true"
android:background="@drawable/focusable_view_bg"
launcher:deferShadowGeneration="true"
diff --git a/res/layout/apps_list_view.xml b/res/layout/apps_list_view.xml
index a726cd8fe..ddcb639b8 100644
--- a/res/layout/apps_list_view.xml
+++ b/res/layout/apps_list_view.xml
@@ -25,7 +25,7 @@
<FrameLayout
android:id="@+id/header"
android:layout_width="match_parent"
- android:layout_height="52dp"
+ android:layout_height="@dimen/apps_search_bar_height"
android:orientation="horizontal"
android:background="@drawable/apps_search_bg">
<LinearLayout
@@ -39,6 +39,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
+ android:layout_marginStart="4dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:contentDescription="@string/all_apps_button_label"
@@ -67,6 +68,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
+ android:layout_marginEnd="6dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:contentDescription="@string/apps_view_search_bar_hint"
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index ab23b842e..196dfca66 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -19,10 +19,11 @@
android:layout_width="@dimen/widget_preview_container_width"
android:layout_height="@dimen/widget_cell_height"
android:layout_weight="1"
- android:layout_marginRight="@dimen/widget_row_divider"
+ android:layout_marginEnd="@dimen/widget_row_divider"
android:orientation="vertical"
android:background="@color/widgets_cell_color"
- android:focusable="true">
+ android:focusable="true"
+ android:gravity="center_horizontal">
<LinearLayout
android:layout_width="wrap_content"
@@ -43,7 +44,6 @@
android:singleLine="true"
android:ellipsize="end"
android:fadingEdge="horizontal"
-
android:textColor="@color/widgets_view_item_text_color"
android:textSize="16sp"
android:textAlignment="viewStart"
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index 12f6401e4..ea95d2407 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -55,17 +55,18 @@
</LinearLayout>
<!-- Widget list -->
- <RelativeLayout
+ <com.android.launcher3.widget.WidgetRowView
+ android:id="@+id/widget_row"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/widget_cell_height"
android:layout_gravity="end"
+ android:layout_marginLeft="@dimen/widget_row_padding"
android:background="@color/widgets_cell_color"
>
<HorizontalScrollView
android:id="@+id/widgets_scroll_container"
android:layout_width="match_parent"
- android:layout_height="@dimen/widget_cell_height"
- android:layout_marginLeft="@dimen/widget_row_padding"
+ android:layout_height="match_parent"
android:scrollbars="none" >
<LinearLayout
android:id="@+id/widgets_cell_list"
@@ -74,5 +75,5 @@
android:orientation="horizontal"
android:background="@color/widget_text_panel"/>
</HorizontalScrollView>
- </RelativeLayout>
+ </com.android.launcher3.widget.WidgetRowView>
</LinearLayout>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 9ecd07dd1..b18464292 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -22,6 +22,7 @@
<dimen name="apps_grid_view_start_margin">64dp</dimen>
<dimen name="apps_view_section_text_size">26sp</dimen>
<dimen name="apps_view_row_height">76dp</dimen>
+ <dimen name="apps_icon_top_bottom_padding">12dp</dimen>
<!-- AppsCustomize -->
<dimen name="widget_preview_label_margin_top">8dp</dimen>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 68fc1ecaf..cec6b7db0 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -16,6 +16,8 @@
<resources>
<dimen name="app_icon_size">72dp</dimen>
+ <dimen name="apps_search_bar_height">56dp</dimen>
+ <dimen name="apps_icon_top_bottom_padding">16dp</dimen>
<!-- QSB -->
<dimen name="toolbar_button_vertical_padding">8dip</dimen>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 4d33b88bc..5447371a4 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -59,6 +59,8 @@
<dimen name="apps_view_fast_scroll_scrubber_touch_inset">-16dp</dimen>
<dimen name="apps_view_fast_scroll_popup_size">64dp</dimen>
<dimen name="apps_view_fast_scroll_text_size">40dp</dimen>
+ <dimen name="apps_search_bar_height">52dp</dimen>
+ <dimen name="apps_icon_top_bottom_padding">8dp</dimen>
<!-- Note: This needs to match the fixed insets for the search box. -->
<dimen name="container_fixed_bounds_inset">8dp</dimen>
@@ -86,7 +88,7 @@
<!-- Widget tray -->
<dimen name="widget_container_inset">8dp</dimen>
- <dimen name="widget_preview_size">120dp</dimen>
+ <dimen name="widget_preview_size">130dp</dimen>
<dimen name="widget_preview_padding_top">8dp</dimen>
<dimen name="widget_preview_label_vertical_padding">8dp</dimen>
<dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
@@ -98,10 +100,10 @@
<dimen name="widget_section_icon_horizontal_padding">16dp</dimen>
<!-- Equation: widget_preview_size + 2 * widget_preview_padding_horizontal -->
- <dimen name="widget_preview_container_width">136dp</dimen>
+ <dimen name="widget_preview_container_width">146dp</dimen>
<dimen name="widget_cell_height">150dp</dimen>
<dimen name="widget_row_padding">8dp</dimen>
- <dimen name="widget_row_divider">1dp</dimen>
+ <dimen name="widget_row_divider">2dp</dimen>
<!-- Padding applied to shortcut previews -->
<dimen name="shortcut_preview_padding_left">0dp</dimen>
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java
index f075e417d..62cb237e1 100644
--- a/src/com/android/launcher3/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/AlphabeticalAppsList.java
@@ -130,17 +130,21 @@ public class AlphabeticalAppsList {
public AppInfo appInfo = null;
// The index of this app not including sections
public int appIndex = -1;
+ // Whether or not this is a predicted app
+ public boolean isPredictedApp;
public static AdapterItem asSectionBreak(int pos, SectionInfo section) {
AdapterItem item = new AdapterItem();
item.position = pos;
item.isSectionHeader = true;
item.sectionInfo = section;
+ section.sectionBreakItem = item;
return item;
}
public static AdapterItem asApp(int pos, SectionInfo section, String sectionName,
- int sectionAppIndex, AppInfo appInfo, int appIndex) {
+ int sectionAppIndex, AppInfo appInfo, int appIndex,
+ boolean isPredictedApp) {
AdapterItem item = new AdapterItem();
item.position = pos;
item.isSectionHeader = false;
@@ -149,6 +153,7 @@ public class AlphabeticalAppsList {
item.sectionAppIndex = sectionAppIndex;
item.appInfo = appInfo;
item.appIndex = appIndex;
+ item.isPredictedApp = isPredictedApp;
return item;
}
}
@@ -168,6 +173,7 @@ public class AlphabeticalAppsList {
private List<AdapterItem> mSectionedFilteredApps = new ArrayList<>();
private List<SectionInfo> mSections = new ArrayList<>();
private List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
+ private List<ComponentName> mPredictedApps = new ArrayList<>();
private RecyclerView.Adapter mAdapter;
private Filter mFilter;
private AlphabeticIndexCompat mIndexer;
@@ -252,6 +258,17 @@ public class AlphabeticalAppsList {
}
/**
+ * Sets the current set of predicted apps. Since this can be called before we get the full set
+ * of applications, we should merge the results only in onAppsUpdated() which is idempotent.
+ */
+ public void setPredictedApps(List<ComponentName> apps) {
+ mPredictedApps.clear();
+ mPredictedApps.addAll(apps);
+ onAppsUpdated();
+ mAdapter.notifyDataSetChanged();
+ }
+
+ /**
* Sets the current set of apps.
*/
public void setApps(List<AppInfo> apps) {
@@ -336,7 +353,7 @@ public class AlphabeticalAppsList {
// Sort the list of apps
Collections.sort(mApps, mAppNameComparator.getComparator());
- // Recreate the filtered and sectioned apps (for convenience for the grid layout)
+ // Prepare to update the list of sections, filtered apps, etc.
mFilteredApps.clear();
mSections.clear();
mSectionedFilteredApps.clear();
@@ -346,36 +363,62 @@ public class AlphabeticalAppsList {
FastScrollSectionInfo lastFastScrollerSectionInfo = null;
int position = 0;
int appIndex = 0;
- int numApps = mApps.size();
- for (AppInfo info : mApps) {
- String sectionName = mIndexer.computeSectionName(info.title);
+ List<AppInfo> allApps = new ArrayList<>();
+
+ // Add the predicted apps to the combined list
+ int numPredictedApps = 0;
+ if (mPredictedApps != null && !mPredictedApps.isEmpty() && !hasFilter()) {
+ for (ComponentName cn : mPredictedApps) {
+ for (AppInfo info : mApps) {
+ if (cn.equals(info.componentName)) {
+ allApps.add(info);
+ numPredictedApps++;
+ break;
+ }
+ }
+ // Stop at the number of predicted apps
+ if (numPredictedApps == mNumAppsPerRow) {
+ break;
+ }
+ }
+ }
+
+ // Add all the other apps to the combined list
+ allApps.addAll(mApps);
+
+ // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
+ // combined list
+ int numApps = allApps.size();
+ for (int i = 0; i < numApps; i++) {
+ boolean isPredictedApp = i < numPredictedApps;
+ AppInfo info = allApps.get(i);
+ String sectionName = isPredictedApp ? "" : mIndexer.computeSectionName(info.title);
// Check if we want to retain this app
if (mFilter != null && !mFilter.retainApp(info, sectionName)) {
continue;
}
- // Create a new section if necessary
- if (lastSectionInfo == null || !sectionName.equals(lastSectionName)) {
+ // Create a new section if the section names do not match
+ if (lastSectionInfo == null ||
+ (!isPredictedApp && !sectionName.equals(lastSectionName))) {
lastSectionName = sectionName;
lastSectionInfo = new SectionInfo();
- mSections.add(lastSectionInfo);
lastFastScrollerSectionInfo = new FastScrollSectionInfo(sectionName,
(float) appIndex / numApps);
+ mSections.add(lastSectionInfo);
mFastScrollerSections.add(lastFastScrollerSectionInfo);
- // Create a new section item, this item is used to break the flow of items in the
- // list
- AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
+ // Create a new section item to break the flow of items in the list
if (!AppsContainerView.GRID_HIDE_SECTION_HEADERS && !hasFilter()) {
- lastSectionInfo.sectionBreakItem = sectionItem;
+ AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
mSectionedFilteredApps.add(sectionItem);
}
}
// Create an app item
AdapterItem appItem = AdapterItem.asApp(position++, lastSectionInfo, sectionName,
- lastSectionInfo.numApps++, info, appIndex++);
+ lastSectionInfo.numApps++, info, appIndex++, isPredictedApp);
if (lastSectionInfo.firstAppItem == null) {
lastSectionInfo.firstAppItem = appItem;
lastFastScrollerSectionInfo.appItem = appItem;
@@ -384,8 +427,8 @@ public class AlphabeticalAppsList {
mFilteredApps.add(info);
}
+ // Go through each section and try and merge some of the sections
if (AppsContainerView.GRID_MERGE_SECTIONS && !hasFilter()) {
- // Go through each section and try and merge some of the sections
int minNumAppsPerRow = (int) Math.ceil(mNumAppsPerRow / 2f);
int sectionAppCount = 0;
for (int i = 0; i < mSections.size(); i++) {
diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java
index 6556cf920..edb6f0c6e 100644
--- a/src/com/android/launcher3/AppsContainerRecyclerView.java
+++ b/src/com/android/launcher3/AppsContainerRecyclerView.java
@@ -229,7 +229,7 @@ public class AppsContainerRecyclerView extends BaseContainerRecyclerView {
* Draws the fast scroller popup.
*/
private void drawFastScrollerPopup(Canvas canvas) {
- if (mFastScrollAlpha > 0f) {
+ if (mFastScrollAlpha > 0f && !mFastScrollSectionName.isEmpty()) {
int x;
int y;
boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
@@ -381,16 +381,16 @@ public class AppsContainerRecyclerView extends BaseContainerRecyclerView {
}
/**
- * Returns the row index for a given position in the list.
+ * Returns the row index for a app index in the list.
*/
- private int findRowForAppIndex(int position) {
+ private int findRowForAppIndex(int index) {
List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections();
int appIndex = 0;
int rowCount = 0;
for (AlphabeticalAppsList.SectionInfo info : sections) {
int numRowsInSection = (int) Math.ceil((float) info.numApps / mNumAppsPerRow);
- if (appIndex + info.numApps > position) {
- return rowCount + ((position - appIndex) / mNumAppsPerRow);
+ if (appIndex + info.numApps > index) {
+ return rowCount + ((index - appIndex) / mNumAppsPerRow);
}
appIndex += info.numApps;
rowCount += numRowsInSection;
diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java
index aa6c05993..b8d30d081 100644
--- a/src/com/android/launcher3/AppsContainerView.java
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3;
+import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
@@ -111,6 +112,13 @@ public class AppsContainerView extends BaseContainerView implements DragSource,
}
/**
+ * Sets the current set of predicted apps.
+ */
+ public void setPredictedApps(List<ComponentName> apps) {
+ mApps.setPredictedApps(apps);
+ }
+
+ /**
* Sets the current set of apps.
*/
public void setApps(List<AppInfo> apps) {
diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java
index 259740c60..9ecb2eeb6 100644
--- a/src/com/android/launcher3/AppsGridAdapter.java
+++ b/src/com/android/launcher3/AppsGridAdapter.java
@@ -35,13 +35,11 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> {
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
public View mContent;
- public boolean mIsSectionHeader;
public boolean mIsEmptyRow;
- public ViewHolder(View v, boolean isSectionHeader, boolean isEmptyRow) {
+ public ViewHolder(View v, boolean isEmptyRow) {
super(v);
mContent = v;
- mIsSectionHeader = isSectionHeader;
mIsEmptyRow = isEmptyRow;
}
}
@@ -93,13 +91,29 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> {
}
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
+ boolean hasDrawnPredictedAppDivider = false;
int childCount = parent.getChildCount();
int lastSectionTop = 0;
int lastSectionHeight = 0;
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
ViewHolder holder = (ViewHolder) parent.getChildViewHolder(child);
- if (shouldDrawItemSection(holder, child, i, items)) {
+ if (!isValidHolderAndChild(holder, child, items)) {
+ continue;
+ }
+
+ 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();
+ int iconInset = (((right - left) / mAppsPerRow) - grid.allAppsIconSizePx) / 2;
+ c.drawLine(left + iconInset, top, right - iconInset, top, mPredictedAppsDividerPaint);
+ hasDrawnPredictedAppDivider = true;
+
+ } else if (shouldDrawItemSection(holder, i, items)) {
// At this point, we only draw sections for each section break;
int viewTopOffset = (2 * child.getPaddingTop());
int pos = holder.getPosition();
@@ -186,9 +200,9 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> {
}
/**
- * Returns whether to draw the section for the given child.
+ * Returns whether we consider this a valid view holder for us to draw a divider or section for.
*/
- private boolean shouldDrawItemSection(ViewHolder holder, View child, int childIndex,
+ private boolean isValidHolderAndChild(ViewHolder holder, View child,
List<AlphabeticalAppsList.AdapterItem> items) {
// Ensure item is not already removed
GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams)
@@ -200,18 +214,44 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> {
if (holder == null) {
return false;
}
+ // Ensure we have a holder position
+ int pos = holder.getPosition();
+ if (pos < 0 || pos >= items.size()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether to draw the divider for a given child.
+ */
+ private boolean shouldDrawItemDivider(ViewHolder holder, List<AlphabeticalAppsList.AdapterItem> items) {
+ int pos = holder.getPosition();
+ return items.get(pos).isPredictedApp;
+ }
+
+ /**
+ * Returns whether to draw the section for the given child.
+ */
+ private boolean shouldDrawItemSection(ViewHolder holder, int childIndex,
+ List<AlphabeticalAppsList.AdapterItem> items) {
+ int pos = holder.getPosition();
+ AlphabeticalAppsList.AdapterItem item = items.get(pos);
+
// Ensure it's not an empty row
if (holder.mIsEmptyRow) {
return false;
}
- // Ensure we have a holder position
- int pos = holder.getPosition();
- if (pos <= 0 || pos >= items.size()) {
+ // Ensure this is not a section break
+ if (item.isSectionHeader) {
+ return false;
+ }
+ // Ensure this is not a predicted app
+ if (item.isPredictedApp) {
return false;
}
// Draw the section header for the first item in each section
- return (childIndex == 0) ||
- (items.get(pos - 1).isSectionHeader && !items.get(pos).isSectionHeader);
+ return (childIndex == 0) || (items.get(pos - 1).isSectionHeader && !item.isSectionHeader);
}
}
@@ -232,6 +272,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> {
@Thunk int mStartMargin;
@Thunk int mSectionHeaderOffset;
@Thunk Paint mSectionTextPaint;
+ @Thunk Paint mPredictedAppsDividerPaint;
public AppsGridAdapter(Context context, AlphabeticalAppsList apps, int appsPerRow,
@@ -254,11 +295,17 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> {
mSectionHeaderOffset = res.getDimensionPixelSize(R.dimen.apps_grid_section_y_offset);
}
mPaddingStart = res.getDimensionPixelSize(R.dimen.apps_container_inset);
+
mSectionTextPaint = new Paint();
mSectionTextPaint.setTextSize(res.getDimensionPixelSize(
R.dimen.apps_view_section_text_size));
mSectionTextPaint.setColor(res.getColor(R.color.apps_view_section_text_color));
mSectionTextPaint.setAntiAlias(true);
+
+ mPredictedAppsDividerPaint = new Paint();
+ mPredictedAppsDividerPaint.setStrokeWidth(DynamicGrid.pxFromDp(1.5f, res.getDisplayMetrics()));
+ mPredictedAppsDividerPaint.setColor(0x10000000);
+ mPredictedAppsDividerPaint.setAntiAlias(true);
}
/**
@@ -313,10 +360,9 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> {
switch (viewType) {
case EMPTY_VIEW_TYPE:
return new ViewHolder(mLayoutInflater.inflate(R.layout.apps_empty_view, parent,
- false), false /* isSectionRow */, true /* isEmptyRow */);
+ false), true /* isEmptyRow */);
case SECTION_BREAK_VIEW_TYPE:
- return new ViewHolder(new View(parent.getContext()), true /* isSectionRow */,
- false /* isEmptyRow */);
+ return new ViewHolder(new View(parent.getContext()), false /* isEmptyRow */);
case ICON_VIEW_TYPE:
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
R.layout.apps_grid_row_icon_view, parent, false);
@@ -324,7 +370,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> {
icon.setOnClickListener(mIconClickListener);
icon.setOnLongClickListener(mIconLongClickListener);
icon.setFocusable(true);
- return new ViewHolder(icon, false /* isSectionRow */, false /* isEmptyRow */);
+ return new ViewHolder(icon, false /* isEmptyRow */);
default:
throw new RuntimeException("Unexpected view type");
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 918517ebd..7a6e9a20a 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -69,8 +69,10 @@ public class DeviceProfile {
String name;
float minWidthDps;
float minHeightDps;
- public float numRows;
- public float numColumns;
+ public int numRows;
+ public int numColumns;
+ public int numFolderRows;
+ public int numFolderColumns;
float numHotseatIcons;
float iconSize;
private float iconTextSize;
@@ -80,12 +82,11 @@ public class DeviceProfile {
int defaultLayoutId;
boolean isLandscape;
- boolean isTablet;
- boolean isLargeTablet;
+ public boolean isTablet;
+ public boolean isLargeTablet;
public boolean isLayoutRtl;
boolean transposeLayoutWithOrientation;
-
int desiredWorkspaceLeftRightMarginPx;
public int edgeMarginPx;
Rect defaultWidgetPadding;
@@ -138,8 +139,9 @@ public class DeviceProfile {
private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>();
- DeviceProfile(String n, float w, float h, float r, float c,
- float is, float its, float hs, float his, int dlId) {
+ DeviceProfile(String n, float w, float h,
+ int r, int c, int fr, int fc,
+ float is, float its, float hs, float his, int dlId) {
// Ensure that we have an odd number of hotseat items (since we need to place all apps)
if (hs % 2 == 0) {
throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
@@ -148,8 +150,12 @@ public class DeviceProfile {
name = n;
minWidthDps = w;
minHeightDps = h;
+
numRows = r;
numColumns = c;
+ numFolderRows = fr;
+ numFolderColumns = fc;
+
iconSize = is;
iconTextSize = its;
numHotseatIcons = hs;
@@ -210,6 +216,9 @@ public class DeviceProfile {
// Snap to the closest column count
numColumns = closestProfile.numColumns;
+ numFolderRows = closestProfile.numFolderRows;
+ numFolderColumns = closestProfile.numFolderColumns;
+
// Snap to the closest hotseat size
numHotseatIcons = closestProfile.numHotseatIcons;
hotseatAllAppsRank = (int) (numHotseatIcons / 2);
@@ -266,8 +275,8 @@ public class DeviceProfile {
DeviceProfile partnerDp = p.getDeviceProfileOverride(dm);
if (partnerDp != null) {
if (partnerDp.numRows > 0 && partnerDp.numColumns > 0) {
- numRows = partnerDp.numRows;
- numColumns = partnerDp.numColumns;
+ numRows = numFolderRows = partnerDp.numRows;
+ numColumns = numFolderColumns = partnerDp.numColumns;
}
if (partnerDp.allAppsShortEdgeCount > 0 && partnerDp.allAppsLongEdgeCount > 0) {
allAppsShortEdgeCount = partnerDp.allAppsShortEdgeCount;
diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java
index 24da97fc6..d22427f44 100644
--- a/src/com/android/launcher3/DynamicGrid.java
+++ b/src/com/android/launcher3/DynamicGrid.java
@@ -59,30 +59,30 @@ public class DynamicGrid {
DEFAULT_ICON_SIZE_PX = pxFromDp(DEFAULT_ICON_SIZE_DP, dm);
// Our phone profiles include the bar sizes in each orientation
deviceProfiles.add(new DeviceProfile("Super Short Stubby",
- 255, 300, 2, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
+ 255, 300, 2, 3, 2, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Shorter Stubby",
- 255, 400, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
+ 255, 400, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Short Stubby",
- 275, 420, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+ 275, 420, 3, 4, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Stubby",
- 255, 450, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+ 255, 450, 3, 4, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Nexus S",
- 296, 491.33f, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+ 296, 491.33f, 4, 4, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Nexus 4",
- 335, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
+ 335, 567, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Nexus 5",
- 359, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
+ 359, 567, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Large Phone",
- 406, 694, 5, 5, 64, 14.4f, 5, 56, R.xml.default_workspace_5x5));
+ 406, 694, 5, 5, 4, 4, 64, 14.4f, 5, 56, R.xml.default_workspace_5x5));
// The tablet profile is odd in that the landscape orientation
// also includes the nav bar on the side
deviceProfiles.add(new DeviceProfile("Nexus 7",
- 575, 904, 5, 6, 72, 14.4f, 7, 60, R.xml.default_workspace_5x6));
+ 575, 904, 5, 6, 4, 5, 72, 14.4f, 7, 60, R.xml.default_workspace_5x6));
// Larger tablet profiles always have system bars on the top & bottom
deviceProfiles.add(new DeviceProfile("Nexus 10",
- 727, 1207, 5, 6, 76, 14.4f, 7, 64, R.xml.default_workspace_5x6));
+ 727, 1207, 5, 6, 4, 5, 76, 14.4f, 7, 64, R.xml.default_workspace_5x6));
deviceProfiles.add(new DeviceProfile("20-inch Tablet",
- 1527, 2527, 7, 7, 100, 20, 7, 72, R.xml.default_workspace_4x4));
+ 1527, 2527, 7, 7, 6, 6, 100, 20, 7, 72, R.xml.default_workspace_4x4));
mMinWidth = dpiFromPx(minWidthPx, dm);
mMinHeight = dpiFromPx(minHeightPx, dm);
mProfile = new DeviceProfile(context, deviceProfiles,
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 63550827b..05b2bbf67 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -51,9 +51,6 @@ public class FolderPagedView extends PagedView {
private static final int[] sTempPosArray = new int[2];
- // TODO: Remove this restriction
- private static final int MAX_ITEMS_PER_PAGE = 4;
-
public final boolean rtlLayout;
private final LayoutInflater mInflater;
@@ -80,13 +77,8 @@ public class FolderPagedView extends PagedView {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- if (ALLOW_FOLDER_SCROLL) {
- mMaxCountX = Math.min((int) grid.numColumns, MAX_ITEMS_PER_PAGE);
- mMaxCountY = Math.min((int) grid.numRows, MAX_ITEMS_PER_PAGE);
- } else {
- mMaxCountX = (int) grid.numColumns;
- mMaxCountY = (int) grid.numRows;
- }
+ mMaxCountX = (int) grid.numFolderColumns;
+ mMaxCountY = (int) grid.numFolderRows;
mMaxItemsPerPage = mMaxCountX * mMaxCountY;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b17a92f47..16e4ce644 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -64,6 +64,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
+import android.preference.PreferenceManager;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -1020,16 +1021,22 @@ public class Launcher extends Activity
if (mOnResumeState == State.WORKSPACE) {
showWorkspace(false);
} else if (mOnResumeState == State.APPS) {
- showAppsView(false /* animated */, false /* resetListToTop */);
+ // 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
+ showAppsView(false /* animated */, false /* resetListToTop */,
+ false /* updatePredictedApps */);
} else if (mOnResumeState == State.WIDGETS) {
showWidgetsView(false, false);
}
mOnResumeState = State.NONE;
// Restore the apps state if we are in all apps
- if (!Launcher.DISABLE_ALL_APPS_SEARCH_INTEGRATION && mState == State.APPS) {
- if (mLauncherCallbacks != null) {
- mLauncherCallbacks.onAllAppsShown();
+ if (!Launcher.DISABLE_ALL_APPS_SEARCH_INTEGRATION) {
+ // Otherwise, notify the callbacks if we are in all apps mode
+ if (mState == State.APPS) {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onAllAppsShown();
+ }
}
}
@@ -2621,7 +2628,9 @@ public class Launcher extends Activity
if (isAppsViewVisible()) {
showWorkspace(true);
} else {
- showAppsView(true /* animated */, false /* resetListToTop */);
+ // Try and refresh the set of predicted apps before we enter launcher
+ showAppsView(true /* animated */, false /* resetListToTop */,
+ true /* updatePredictedApps */);
}
}
@@ -3399,10 +3408,13 @@ public class Launcher extends Activity
/**
* Shows the apps view.
*/
- void showAppsView(boolean animated, boolean resetListToTop) {
+ void showAppsView(boolean animated, boolean resetListToTop, boolean updatePredictedApps) {
if (resetListToTop) {
mAppsView.scrollToTop();
}
+ if (updatePredictedApps) {
+ tryAndUpdatePredictedApps();
+ }
showAppsOrWidgets(animated, State.APPS);
}
@@ -3511,12 +3523,26 @@ public class Launcher extends Activity
void exitSpringLoadedDragMode() {
if (mState == State.APPS_SPRING_LOADED) {
- showAppsView(true, false);
+ showAppsView(true /* animated */, false /* resetListToTop */,
+ false /* updatePredictedApps */);
} else if (mState == State.WIDGETS_SPRING_LOADED) {
showWidgetsView(true, false);
}
}
+ /**
+ * Updates the set of predicted apps if it hasn't been updated since the last time Launcher was
+ * resumed.
+ */
+ private void tryAndUpdatePredictedApps() {
+ if (mLauncherCallbacks != null) {
+ List<ComponentName> apps = mLauncherCallbacks.getPredictedApps();
+ if (!apps.isEmpty()) {
+ mAppsView.setPredictedApps(apps);
+ }
+ }
+ }
+
void lockAllApps() {
// TODO
}
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 25c86c977..0124d1f28 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -11,6 +11,7 @@ import android.view.ViewGroup;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* LauncherCallbacks is an interface used to extend the Launcher activity. It includes many hooks
@@ -90,6 +91,7 @@ public interface LauncherCallbacks {
public boolean overrideWallpaperDimensions();
public boolean isLauncherPreinstalled();
public boolean overrideAllAppsSearch();
+ public List<ComponentName> getPredictedApps();
/**
* Returning true will immediately result in a call to {@link #setLauncherOverlayView(ViewGroup,
diff --git a/src/com/android/launcher3/LauncherExtension.java b/src/com/android/launcher3/LauncherExtension.java
index 8174af045..14ad6016c 100644
--- a/src/com/android/launcher3/LauncherExtension.java
+++ b/src/com/android/launcher3/LauncherExtension.java
@@ -15,6 +15,7 @@ import android.view.ViewGroup;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* This class represents a very trivial LauncherExtension. It primarily serves as a simple
@@ -259,6 +260,11 @@ public class LauncherExtension extends Launcher {
}
@Override
+ public List<ComponentName> getPredictedApps() {
+ return new ArrayList<>();
+ }
+
+ @Override
public boolean isLauncherPreinstalled() {
return false;
}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 27b7e6df5..877937151 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -49,7 +49,16 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
private static final boolean DEBUG = false;
private static final int FADE_IN_DURATION_MS = 90;
- private int mPresetPreviewSize;
+
+ /** Widget cell width is calculated by multiplying this factor to grid cell width. */
+ private static final float WIDTH_SCALE = 2.8f;
+
+ /** Widget preview width is calculated by multiplying this factor to the widget cell width. */
+ private static final float PREVIEW_SCALE = 0.9f;
+
+ private static int mPresetPreviewSize;
+ private static int mSize;
+ private static int mDividerWidth;
private ImageView mWidgetImage;
private TextView mWidgetName;
@@ -76,12 +85,22 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
final Resources r = context.getResources();
mDimensionsFormatString = r.getString(R.string.widget_dims_format);
- mPresetPreviewSize = r.getDimensionPixelSize(R.dimen.widget_preview_size);
+ setContainerWidth();
setWillNotDraw(false);
setClipToPadding(false);
setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
+ }
+ private void setContainerWidth() {
+ // Do nothing if already set
+ if (mSize > 0) {
+ return;
+ }
+ DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
+ mSize = (int) (profile.cellWidthPx * WIDTH_SCALE);
+ mPresetPreviewSize = (int) (profile.cellWidthPx * WIDTH_SCALE * PREVIEW_SCALE);
+ mDividerWidth = getResources().getDimensionPixelSize(R.dimen.widget_row_divider);
}
@Override
@@ -98,6 +117,12 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(MeasureSpec.makeMeasureSpec(mSize, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(mSize, MeasureSpec.EXACTLY));
+ }
+
/**
* Called to clear the view and free attached resources. (e.g., {@link Bitmap}
*/
@@ -108,6 +133,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
mWidgetImage.setImageDrawable(null);
mWidgetName.setText(null);
mWidgetDims.setText(null);
+ setSeparator(true);
if (mActiveRequest != null) {
mActiveRequest.cleanup();
@@ -228,4 +254,11 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
}
return "";
}
+
+ public void setSeparator(boolean enable) {
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();
+ lp.setMarginEnd(enable? mDividerWidth : 0);
+ setLayoutParams(lp);
+ requestLayout();
+ }
}
diff --git a/src/com/android/launcher3/widget/WidgetRowView.java b/src/com/android/launcher3/widget/WidgetRowView.java
new file mode 100644
index 000000000..05760ae48
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetRowView.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DynamicGrid;
+import com.android.launcher3.LauncherAppState;
+
+/**
+ * Represents the individual cell of the widget inside the widget tray.
+ */
+public class WidgetRowView extends LinearLayout {
+
+ private static final int PRESET_INDENT_SIZE_TABLET = 56;
+
+ /** Widget row width is calculated by multiplying this factor to grid cell width. */
+ private static final float HEIGHT_SCALE = 2.8f;
+
+ static int sIndent = 0;
+ static int sHeight = 0;
+
+ public WidgetRowView(Context context) {
+ this(context, null);
+ }
+
+ public WidgetRowView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public WidgetRowView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setContainerHeight();
+ setWillNotDraw(false);
+ setClipToPadding(false);
+ setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
+ }
+
+ /**
+ * Sets the widget cell container size based on the physical dimension of the device.
+ */
+ private void setContainerHeight() {
+ // Do nothing if already set
+ if (sHeight > 0) {
+ return;
+ }
+
+ Resources r = getResources();
+ DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
+ if (profile.isLargeTablet || profile.isTablet) {
+ sIndent = DynamicGrid.pxFromDp(PRESET_INDENT_SIZE_TABLET, r.getDisplayMetrics());
+ }
+ sHeight = (int) (profile.cellWidthPx * HEIGHT_SCALE);
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index a7728a11b..8b0a43b2f 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -23,6 +23,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.launcher3.IconCache;
@@ -105,6 +106,10 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
// set up touch.
widget.setOnClickListener(mIconClickListener);
widget.setOnLongClickListener(mIconLongClickListener);
+ // Add a devider if it is not the last item.
+ if (i == diff - 1) {
+ widget.setSeparator(false);
+ }
row.addView(widget);
}
} else if (diff < 0) {
@@ -156,6 +161,11 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
ViewGroup container = (ViewGroup) mLayoutInflater.inflate(
R.layout.widgets_list_row_view, parent, false);
+ WidgetRowView row = (WidgetRowView) container.findViewById(R.id.widget_row);
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) row.getLayoutParams();
+ lp.setMarginStart(WidgetRowView.sIndent);
+ lp.height = WidgetRowView.sHeight;
+ row.setLayoutParams(lp);
return new WidgetsRowViewHolder(container);
}