Merge "Moving saving state transtion listener logic to individual views" into ub-launcher3-master
diff --git a/res/layout/appwidget_error.xml b/res/layout/appwidget_error.xml
index 708ece4..d6bd0c5 100644
--- a/res/layout/appwidget_error.xml
+++ b/res/layout/appwidget_error.xml
@@ -19,6 +19,7 @@
android:layout_height="match_parent"
android:gravity="center"
android:elevation="2dp"
+ android:theme="@style/WidgetContainerTheme"
android:background="@drawable/quantum_panel_dark"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
android:textColor="@color/widgets_view_item_text_color"
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 3423835..32bccb8 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -27,6 +27,7 @@
<enum name="all_apps" value="1" />
<enum name="folder" value="2" />
<enum name="widget_section" value="3" />
+ <enum name="shortcut_popup" value="4" />
</attr>
<attr name="deferShadowGeneration" format="boolean" />
<attr name="customShadows" format="boolean" />
diff --git a/res/values/styles.xml b/res/values/styles.xml
index bb0bc2f..4e70f43 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -108,6 +108,7 @@
<item name="android:shadowRadius">0</item>
<item name="customShadows">false</item>
<item name="layoutHorizontal">true</item>
+ <item name="iconDisplay">shortcut_popup</item>
<item name="iconSizeOverride">@dimen/deep_shortcut_icon_size</item>
</style>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 979c950..84b504e 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -618,7 +618,9 @@
public void setIsHotseat(boolean isHotseat) {
mIsHotseat = isHotseat;
- mShortcutsAndWidgets.setIsHotseat(isHotseat);
+ mShortcutsAndWidgets.setContainerType(isHotseat
+ ? ShortcutAndWidgetContainer.HOTSEAT
+ : ShortcutAndWidgetContainer.DEFAULT);
}
public boolean isHotseat() {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index cc21920..59ec56a 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -112,6 +112,7 @@
public int hotseatIconSizePx;
public int hotseatBarHeightPx;
private int hotseatBarTopPaddingPx;
+ private int hotseatBarBottomPaddingPx;
private int hotseatLandGutterPx;
// All apps
@@ -185,6 +186,7 @@
hotseatBarHeightPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height);
hotseatBarTopPaddingPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
+ hotseatBarBottomPaddingPx = 0;
hotseatLandGutterPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_gutter_width);
// Determine sizes.
@@ -207,7 +209,18 @@
// In multi-window mode, we can have widthPx = availableWidthPx
// and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles'
// widthPx and heightPx values where it's needed.
- return new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y, isLandscape);
+ DeviceProfile profile = new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y,
+ isLandscape);
+
+ // Hide labels on the workspace.
+ profile.iconTextSizePx = 0;
+ profile.cellHeightPx = profile.iconSizePx + profile.iconDrawablePaddingPx
+ + Utilities.calculateTextHeight(profile.iconTextSizePx);
+
+ // The nav bar is black so we add bottom padding to visually center hotseat icons.
+ profile.hotseatBarBottomPaddingPx = profile.hotseatBarTopPaddingPx;
+
+ return profile;
}
public void addLauncherLayoutChangedListener(LauncherLayoutChangeListener listener) {
@@ -396,7 +409,8 @@
availablePaddingX = (int) Math.min(availablePaddingX,
width * MAX_HORIZONTAL_PADDING_PERCENT);
int availablePaddingY = Math.max(0, height - topWorkspacePadding - paddingBottom
- - (int) (2 * inv.numRows * cellHeightPx));
+ - (2 * inv.numRows * cellHeightPx) - hotseatBarTopPaddingPx
+ - hotseatBarBottomPaddingPx);
padding.set(availablePaddingX / 2, topWorkspacePadding + availablePaddingY / 2,
availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
} else {
@@ -529,7 +543,7 @@
lp.height = hotseatBarHeightPx + mInsets.bottom;
hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left,
hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right,
- mInsets.bottom);
+ hotseatBarBottomPaddingPx + mInsets.bottom);
} else {
// For phones, layout the hotseat without any bottom margin
// to ensure that we have space for the folders
@@ -538,7 +552,7 @@
lp.height = hotseatBarHeightPx + mInsets.bottom;
hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left,
hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right,
- mInsets.bottom);
+ hotseatBarBottomPaddingPx + mInsets.bottom);
}
hotseat.setLayoutParams(lp);
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index d3e5350..657b024 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -20,10 +20,8 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
-import android.os.DeadObjectException;
-import android.os.TransactionTooLargeException;
+import android.util.SparseArray;
import android.view.LayoutInflater;
-import android.view.View;
import java.util.ArrayList;
@@ -36,6 +34,7 @@
public class LauncherAppWidgetHost extends AppWidgetHost {
private final ArrayList<Runnable> mProviderChangeListeners = new ArrayList<Runnable>();
+ private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
private Launcher mLauncher;
@@ -45,9 +44,11 @@
}
@Override
- protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
+ protected LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
- return new LauncherAppWidgetHostView(context);
+ LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
+ mViews.put(appWidgetId, view);
+ return view;
}
@Override
@@ -55,15 +56,13 @@
try {
super.startListening();
} catch (Exception e) {
- if (e.getCause() instanceof TransactionTooLargeException ||
- e.getCause() instanceof DeadObjectException) {
- // We're willing to let this slide. The exception is being caused by the list of
- // RemoteViews which is being passed back. The startListening relationship will
- // have been established by this point, and we will end up populating the
- // widgets upon bind anyway. See issue 14255011 for more context.
- } else {
+ if (!Utilities.isBinderSizeError(e)) {
throw new RuntimeException(e);
}
+ // We're willing to let this slide. The exception is being caused by the list of
+ // RemoteViews which is being passed back. The startListening relationship will
+ // have been established by this point, and we will end up populating the
+ // widgets upon bind anyway. See issue 14255011 for more context.
}
}
@@ -98,7 +97,24 @@
lahv.updateLastInflationOrientation();
return lahv;
} else {
- return super.createView(context, appWidgetId, appWidget);
+ try {
+ return super.createView(context, appWidgetId, appWidget);
+ } catch (Exception e) {
+ if (!Utilities.isBinderSizeError(e)) {
+ throw new RuntimeException(e);
+ }
+
+ // If the exception was thrown while fetching the remote views, let the view stay.
+ // This will ensure that if the widget posts a valid update later, the view
+ // will update.
+ LauncherAppWidgetHostView view = mViews.get(appWidgetId);
+ if (view == null) {
+ view = onCreateView(mLauncher, appWidgetId, appWidget);
+ }
+ view.setAppWidget(appWidgetId, appWidget);
+ view.switchToErrorView();
+ return view;
+ }
}
}
@@ -114,4 +130,16 @@
// launcher spans accordingly.
info.initSpans();
}
+
+ @Override
+ public void deleteAppWidgetId(int appWidgetId) {
+ super.deleteAppWidgetId(appWidgetId);
+ mViews.remove(appWidgetId);
+ }
+
+ @Override
+ protected void clearViews() {
+ super.clearViews();
+ mViews.clear();
+ }
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index b34d1ff..a4ea449 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -77,7 +77,7 @@
mContext = context;
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mInflater = LayoutInflater.from(context);
setAccessibilityDelegate(Launcher.getLauncher(context).getAccessibilityDelegate());
setBackgroundResource(R.drawable.widget_internal_focus_bg);
@@ -316,6 +316,11 @@
setSelected(childIsFocused);
}
+ public void switchToErrorView() {
+ // Update the widget with 0 Layout id, to reset the view to error view.
+ updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
try {
@@ -324,8 +329,7 @@
post(new Runnable() {
@Override
public void run() {
- // Update the widget with 0 Layout id, to reset the view to error view.
- updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
+ switchToErrorView();
}
});
}
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index c8bb793..dafc81a 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -18,13 +18,25 @@
import android.app.WallpaperManager;
import android.content.Context;
-import android.graphics.Paint;
import android.graphics.Rect;
+import android.support.annotation.IntDef;
import android.view.View;
import android.view.ViewGroup;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
public class ShortcutAndWidgetContainer extends ViewGroup {
- static final String TAG = "CellLayoutChildren";
+ static final String TAG = "ShortcutAndWidgetContainer";
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DEFAULT, HOTSEAT, FOLDER})
+ public @interface ContainerType{}
+ public static final int DEFAULT = 0;
+ public static final int HOTSEAT = 1;
+ public static final int FOLDER = 2;
+
+ private int mContainerType = DEFAULT;
// These are temporary variables to prevent having to allocate a new object just to
// return an (x, y) value from helper functions. Do NOT use them to maintain other state.
@@ -32,8 +44,6 @@
private final WallpaperManager mWallpaperManager;
- private boolean mIsHotseatLayout;
-
private int mCellWidth;
private int mCellHeight;
@@ -101,20 +111,19 @@
mInvertIfRtl = invert;
}
- public void setIsHotseat(boolean isHotseat) {
- mIsHotseatLayout = isHotseat;
- }
-
- int getCellContentWidth() {
- final DeviceProfile grid = mLauncher.getDeviceProfile();
- return Math.min(getMeasuredHeight(), mIsHotseatLayout ?
- grid.hotseatCellWidthPx: grid.cellWidthPx);
+ public void setContainerType(@ContainerType int containerType) {
+ mContainerType = containerType;
}
int getCellContentHeight() {
final DeviceProfile grid = mLauncher.getDeviceProfile();
- return Math.min(getMeasuredHeight(), mIsHotseatLayout ?
- grid.hotseatCellHeightPx : grid.cellHeightPx);
+ int cellContentHeight = grid.cellHeightPx;
+ if (mContainerType == HOTSEAT) {
+ cellContentHeight = grid.hotseatCellHeightPx;
+ } else if (mContainerType == FOLDER) {
+ cellContentHeight = grid.folderCellHeightPx;
+ }
+ return Math.min(getMeasuredHeight(), cellContentHeight);
}
public void measureChild(View child) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e82c32e..416ca8e 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -38,7 +38,9 @@
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
+import android.os.DeadObjectException;
import android.os.PowerManager;
+import android.os.TransactionTooLargeException;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -648,4 +650,9 @@
accessibilityManager.sendAccessibilityEvent(event);
}
}
+
+ public static boolean isBinderSizeError(Exception e) {
+ return e.getCause() instanceof TransactionTooLargeException
+ || e.getCause() instanceof DeadObjectException;
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0dd762f..01d87f4 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2521,6 +2521,7 @@
onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);
} else if (mDragInfo != null) {
final View cell = mDragInfo.cell;
+ boolean droppedOnOriginalCellDuringTransition = false;
if (dropTargetLayout != null && !d.cancelled) {
// Move internally
@@ -2563,6 +2564,10 @@
minSpanY = item.minSpanY;
}
+ droppedOnOriginalCellDuringTransition = mIsSwitchingState
+ && item.screenId == screenId && item.container == container
+ && item.cellX == mTargetCell[0] && item.cellY == mTargetCell[1];
+
int[] resultSpan = new int[2];
mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,
@@ -2620,7 +2625,7 @@
&& !d.accessibleDrag) {
mDelayedResizeRunnable = new Runnable() {
public void run() {
- if (!isPageInTransition() && !mIsSwitchingState) {
+ if (!isPageInTransition()) {
DragLayer dragLayer = mLauncher.getDragLayer();
dragLayer.addResizeFrame(hostView, cellLayout);
}
@@ -2655,6 +2660,17 @@
};
mAnimatingViewIntoPlace = true;
if (d.dragView.hasDrawn()) {
+ if (droppedOnOriginalCellDuringTransition) {
+ // Animate the item to its original position, while simultaneously exiting
+ // spring-loaded mode so the page meets the icon where it was picked up.
+ mLauncher.getDragController().animateDragViewToOriginalPosition(
+ mDelayedResizeRunnable, cell,
+ mStateTransitionAnimation.mSpringLoadedTransitionTime);
+ mLauncher.exitSpringLoadedDragMode();
+ mLauncher.getDropTargetBar().onDragEnd();
+ parent.onDropChild(cell);
+ return;
+ }
final ItemInfo info = (ItemInfo) cell.getTag();
boolean isWidget = info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
|| info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 176540d..5fc1d97 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -73,6 +73,7 @@
private AllAppsSearchBarController mSearchBarController;
private View mSearchContainer;
+ private int mSearchContainerMinHeight;
private ExtendedEditText mSearchInput;
private HeaderElevationController mElevationController;
@@ -98,6 +99,9 @@
mApps.setAdapter(mAdapter);
mLayoutManager = mAdapter.getLayoutManager();
mSearchQueryBuilder = new SpannableStringBuilder();
+ mSearchContainerMinHeight
+ = getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_height);
+
Selection.setSelection(mSearchQueryBuilder, 0);
}
@@ -313,8 +317,9 @@
if (!grid.isVerticalBarLayout()) {
MarginLayoutParams searchContainerLp =
(MarginLayoutParams) mSearchContainer.getLayoutParams();
+
searchContainerLp.height = mLauncher.getDragLayer().getInsets().top
- + grid.hotseatCellHeightPx;
+ + mSearchContainerMinHeight;
mSearchContainer.setLayoutParams(searchContainerLp);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index e11bfc6..67ef5fc 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -295,10 +295,6 @@
mIsInPreDrag = false;
}
- public boolean isInPreDrag() {
- return mIsInPreDrag;
- }
-
/**
* Call this from a drag source view like this:
*
@@ -361,6 +357,8 @@
isDeferred = mDragObject.deferDragViewCleanupPostAnimation;
if (!isDeferred) {
mDragObject.dragView.remove();
+ } else if (mIsInPreDrag) {
+ animateDragViewToOriginalPosition(null, null, -1);
}
mDragObject.dragView = null;
}
@@ -374,6 +372,22 @@
releaseVelocityTracker();
}
+ public void animateDragViewToOriginalPosition(final Runnable onComplete,
+ final View originalIcon, int duration) {
+ Runnable onCompleteRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (originalIcon != null) {
+ originalIcon.setVisibility(View.VISIBLE);
+ }
+ if (onComplete != null) {
+ onComplete.run();
+ }
+ }
+ };
+ mDragObject.dragView.animateTo(mMotionDownX, mMotionDownY, onCompleteRunnable, duration);
+ }
+
private void callOnDragEnd() {
if (mIsInPreDrag && mOptions.preDragCondition != null) {
mOptions.preDragCondition.onPreDragEnd(false /* dragStarted*/);
@@ -738,7 +752,7 @@
if (dropTarget.acceptDrop(mDragObject)) {
if (flingVel != null) {
dropTarget.onFlingToDelete(mDragObject, flingVel);
- } else {
+ } else if (!mIsInPreDrag) {
dropTarget.onDrop(mDragObject);
}
accepted = true;
@@ -749,11 +763,6 @@
if (!mIsInPreDrag) {
mDragObject.dragSource.onDropCompleted(
dropTargetAsView, mDragObject, flingVel != null, accepted);
- } else {
- // Only defer the drag view cleanup if the drag source handles the drop.
- if (!(mDragObject.dragSource instanceof DropTarget)) {
- mDragObject.deferDragViewCleanupPostAnimation = false;
- }
}
}
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 8a2ae94..22e077b 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -23,7 +23,6 @@
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -38,11 +37,9 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.Thunk;
-
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Thunk;
import java.util.Arrays;
@@ -57,6 +54,8 @@
@Thunk Paint mPaint;
private final int mRegistrationX;
private final int mRegistrationY;
+ private final float mInitialScale;
+ private final int[] mTempLoc = new int[2];
private Point mDragVisualizeOffset = null;
private Rect mDragRegion = null;
@@ -138,6 +137,8 @@
mRegistrationX = registrationX;
mRegistrationY = registrationY;
+ mInitialScale = initialScale;
+
// Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
measure(ms, ms);
@@ -356,6 +357,13 @@
applyTranslation();
}
+ public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
+ mTempLoc[0] = toTouchX - mRegistrationX;
+ mTempLoc[1] = toTouchY - mRegistrationY;
+ mDragLayer.animateViewIntoPosition(this, mTempLoc, 1f, mInitialScale, mInitialScale,
+ DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
+ }
+
public void animateShift(final int shiftX, final int shiftY) {
if (mAnim.isStarted()) {
return;
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 2952196..53c12b5 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1331,10 +1331,7 @@
mIsExternalDrag = false;
} else {
currentDragView = mCurrentDragView;
- // The view was never removed from this folder if we are still in the pre-drag.
- if (!mDragController.isInPreDrag()) {
- mContent.addViewForRank(currentDragView, si, mEmptyCellRank);
- }
+ mContent.addViewForRank(currentDragView, si, mEmptyCellRank);
}
if (d.dragView.hasDrawn()) {
@@ -1355,12 +1352,9 @@
mItemsInvalidated = true;
rearrangeChildren();
- // The ShortcutInfo was never removed if we are still in the pre-drag.
- if (!mDragController.isInPreDrag()) {
- // Temporarily suppress the listener, as we did all the work already here.
- try (SuppressInfoChanges s = new SuppressInfoChanges()) {
- mInfo.add(si, false);
- }
+ // Temporarily suppress the listener, as we did all the work already here.
+ try (SuppressInfoChanges s = new SuppressInfoChanges()) {
+ mInfo.add(si, false);
}
// Clear the drag info, as it is no longer being dragged.
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 31ec709..e71c5e9 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -256,6 +256,7 @@
CellLayout page = new CellLayout(getContext());
page.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
page.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
+ page.getShortcutsAndWidgets().setContainerType(ShortcutAndWidgetContainer.FOLDER);
page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
page.setInvertIfRtl(true);
page.setGridSize(mGridCountX, mGridCountY);
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 7286bf5..e3a2b24 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -87,6 +87,7 @@
final int N = packages.length;
FlagOp flagOp = FlagOp.NO_OP;
final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
+ ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, mUser);
switch (mOp) {
case OP_ADD: {
for (int i = 0; i < N; i++) {
@@ -135,15 +136,15 @@
FlagOp.addFlag(ShortcutInfo.FLAG_DISABLED_SUSPENDED) :
FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_SUSPENDED);
if (DEBUG) Log.d(TAG, "mAllAppsList.(un)suspend " + N);
- appsList.updateDisabledFlags(
- ItemInfoMatcher.ofPackages(packageSet, mUser), flagOp);
+ appsList.updateDisabledFlags(matcher, flagOp);
break;
case OP_USER_AVAILABILITY_CHANGE:
flagOp = UserManagerCompat.getInstance(context).isQuietModeEnabled(mUser)
? FlagOp.addFlag(ShortcutInfo.FLAG_DISABLED_QUIET_USER)
: FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_QUIET_USER);
// We want to update all packages for this user.
- appsList.updateDisabledFlags(ItemInfoMatcher.ofUser(mUser), flagOp);
+ matcher = ItemInfoMatcher.ofUser(mUser);
+ appsList.updateDisabledFlags(matcher, flagOp);
break;
}
@@ -219,10 +220,10 @@
}
ComponentName cn = si.getTargetComponent();
- if (cn != null && packageSet.contains(cn.getPackageName())) {
+ if (cn != null && matcher.matches(si, cn)) {
AppInfo appInfo = addedOrUpdatedApps.get(cn);
- if (si.isPromise()) {
+ if (si.isPromise() && mOp == OP_ADD) {
if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
// Auto install icon
PackageManager pm = context.getPackageManager();
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 3953f39..64043f4 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -6,17 +6,14 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.DeadObjectException;
-import android.os.TransactionTooLargeException;
import android.util.Log;
import com.android.launcher3.AppFilter;
import com.android.launcher3.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.config.ProviderConfig;
@@ -24,10 +21,7 @@
import com.android.launcher3.util.Preconditions;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
-import java.util.List;
/**
* Widgets data model that is used by the adapters of the widget views and controllers.
@@ -80,9 +74,7 @@
}
setWidgetsAndShortcuts(widgetsAndShortcuts);
} catch (Exception e) {
- if (!ProviderConfig.IS_DOGFOOD_BUILD &&
- (e.getCause() instanceof TransactionTooLargeException ||
- e.getCause() instanceof DeadObjectException)) {
+ if (!ProviderConfig.IS_DOGFOOD_BUILD && Utilities.isBinderSizeError(e)) {
// the returned value may be incomplete and will not be refreshed until the next
// time Launcher starts.
// TODO: after figuring out a repro step, introduce a dirty bit to check when
diff --git a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java b/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
index f592c57..fcf7122 100644
--- a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
+++ b/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
@@ -196,7 +196,7 @@
}
}
- private void sendPointer(int action, Point point) {
+ protected void sendPointer(int action, Point point) {
MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), action, point.x, point.y, 0);
getInstrumentation().sendPointerSync(event);
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
new file mode 100644
index 0000000..f892e63
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
@@ -0,0 +1,68 @@
+package com.android.launcher3.ui;
+
+import android.graphics.Point;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.MotionEvent;
+
+import com.android.launcher3.R;
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.Condition;
+import com.android.launcher3.util.Wait;
+
+/**
+ * Test for verifying that shortcuts are shown and can be launched after long pressing an app
+ */
+@LargeTest
+public class ShortcutsLaunchTest extends LauncherInstrumentationTestCase {
+
+ private LauncherActivityInfoCompat mSettingsApp;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
+ .getActivityList("com.android.settings", UserHandleCompat.myUserHandle()).get(0);
+ }
+
+ public void testAppLauncher_portrait() throws Exception {
+ lockRotation(true);
+ performTest();
+ }
+
+ public void testAppLauncher_landscape() throws Exception {
+ lockRotation(false);
+ performTest();
+ }
+
+ private void performTest() throws Exception {
+ startLauncher();
+
+ // Open all apps and wait for load complete
+ final UiObject2 appsContainer = openAllApps();
+ assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+
+ // Find settings app and verify shortcuts appear when long pressed
+ UiObject2 icon = scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString()));
+ // Press icon center until shortcuts appear
+ Point iconCenter = icon.getVisibleCenter();
+ sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
+ UiObject2 deepShortcutsContainer = findViewById(R.id.deep_shortcuts_container);
+ assertNotNull(deepShortcutsContainer);
+ sendPointer(MotionEvent.ACTION_UP, iconCenter);
+
+ // Verify that launching a shortcut opens a page with the same text
+ assertTrue(deepShortcutsContainer.getChildCount() > 0);
+ UiObject2 shortcut = deepShortcutsContainer.getChildren().get(0)
+ .findObject(getSelectorForId(R.id.deep_shortcut));
+ shortcut.click();
+ assertTrue(mDevice.wait(Until.hasObject(By.pkg(
+ mSettingsApp.getComponentName().getPackageName())
+ .text(shortcut.getText())), DEFAULT_UI_TIMEOUT));
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
new file mode 100644
index 0000000..f9a0e6e
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
@@ -0,0 +1,74 @@
+package com.android.launcher3.ui;
+
+import android.graphics.Point;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.MotionEvent;
+
+import com.android.launcher3.R;
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.Condition;
+import com.android.launcher3.util.Wait;
+
+/**
+ * Test for dragging a deep shortcut to the home screen.
+ */
+@LargeTest
+public class ShortcutsToHomeTest extends LauncherInstrumentationTestCase {
+
+ private LauncherActivityInfoCompat mSettingsApp;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
+ .getActivityList("com.android.settings", UserHandleCompat.myUserHandle()).get(0);
+ }
+
+ public void testDragIcon_portrait() throws Throwable {
+ lockRotation(true);
+ performTest();
+ }
+
+ public void testDragIcon_landscape() throws Throwable {
+ lockRotation(false);
+ performTest();
+ }
+
+ private void performTest() throws Throwable {
+ clearHomescreen();
+ startLauncher();
+
+ // Open all apps and wait for load complete.
+ final UiObject2 appsContainer = openAllApps();
+ assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+
+ // Find the app and long press it to show shortcuts.
+ UiObject2 icon = scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString()));
+ // Press icon center until shortcuts appear
+ Point iconCenter = icon.getVisibleCenter();
+ sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
+ UiObject2 deepShortcutsContainer = findViewById(R.id.deep_shortcuts_container);
+ assertNotNull(deepShortcutsContainer);
+ sendPointer(MotionEvent.ACTION_UP, iconCenter);
+
+ // Drag the first shortcut to the home screen.
+ assertTrue(deepShortcutsContainer.getChildCount() > 0);
+ UiObject2 shortcut = deepShortcutsContainer.getChildren().get(0)
+ .findObject(getSelectorForId(R.id.deep_shortcut));
+ String shortcutName = shortcut.getText();
+ dragToWorkspace(shortcut, false);
+
+ // Verify that the shortcut works on home screen
+ // (the app opens and has the same text as the shortcut).
+ mDevice.findObject(By.text(shortcutName)).click();
+ assertTrue(mDevice.wait(Until.hasObject(By.pkg(
+ mSettingsApp.getComponentName().getPackageName())
+ .text(shortcutName)), DEFAULT_UI_TIMEOUT));
+ }
+}