Merge "Fixing Virtual nodes getting wrong screen bounds, when dragging in spring loaded mode" into ub-launcher3-calgary
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 27ff789..632aff0 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -60,6 +60,12 @@
android:layout_height="@dimen/dynamic_grid_page_indicator_height"
android:layout_gravity="bottom|left"/>
+ <!-- A place holder view instead of the QSB in transposed layout -->
+ <View
+ android:layout_width="0dp"
+ android:layout_height="10dp"
+ android:id="@+id/workspace_blocked_row" />
+
<include layout="@layout/widgets_view"
android:id="@+id/widgets_view"
android:layout_width="match_parent"
@@ -71,6 +77,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
+
</com.android.launcher3.dragndrop.DragLayer>
</com.android.launcher3.LauncherRootView>
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 6b5bf63..0321631 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -37,6 +37,7 @@
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_gravity="center"
launcher:pageIndicator="@+id/page_indicator">
</com.android.launcher3.Workspace>
@@ -61,6 +62,10 @@
android:id="@+id/drop_target_bar"
layout="@layout/drop_target_bar_horz" />
+ <include
+ layout="@layout/qsb_container"
+ android:id="@+id/qsb_container" />
+
<include layout="@layout/widgets_view"
android:id="@+id/widgets_view"
android:layout_width="match_parent"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 33ad323..86544d3 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -33,6 +33,7 @@
<!-- The workspace contains 5 screens of cells -->
<!-- DO NOT CHANGE THE ID -->
<com.android.launcher3.Workspace
+ android:layout_gravity="center"
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -60,6 +61,10 @@
android:layout_width="match_parent"
android:layout_height="@dimen/dynamic_grid_page_indicator_height" />
+ <include
+ layout="@layout/qsb_container"
+ android:id="@+id/qsb_container" />
+
<include layout="@layout/widgets_view"
android:id="@+id/widgets_view"
android:layout_width="match_parent"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index d55fda7..c4c6aab 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -31,7 +31,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
- android:elevation="2dp"
android:focusable="false"
android:visibility="invisible" />
@@ -41,7 +40,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
- android:elevation="15dp"
android:focusable="true"
android:focusableInTouchMode="true"
android:saveEnabled="false"
diff --git a/res/layout/qsb_container.xml b/res/layout/qsb_container.xml
index 55c7390..b75e3b5 100644
--- a/res/layout/qsb_container.xml
+++ b/res/layout/qsb_container.xml
@@ -18,7 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="0dp"
android:id="@+id/qsb_container"
android:padding="0dp" >
diff --git a/res/values/config.xml b/res/values/config.xml
index f69fb2e..0bb3799 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -74,6 +74,9 @@
<!-- View ID to use for QSB widget -->
<item type="id" name="qsb_widget" />
+ <!-- View ID to use for blocked area on the first screen -->
+ <item type="id" name="workspace_blocked_row" />
+
<!-- View ID used by cell layout to jail its content -->
<item type="id" name="cell_layout_jail_id" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1ac6620..7bd9ff7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -112,6 +112,8 @@
<string name="folder_hint_text">Unnamed Folder</string>
<!-- Accessibility -->
+ <!-- The format string for when an app is temporarily disabled. -->
+ <string name="disabled_app_label">Disabled <xliff:g id="app_name" example="Messenger">%1$s</xliff:g></string>
<skip />
<!-- The format string for default page scroll text [CHAR_LIMIT=none] -->
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index ca60d5c..33e4e2a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -153,34 +153,16 @@
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
boolean promiseStateChanged) {
- Bitmap b = info.getIcon(iconCache);
-
- FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(b);
- if (info.isDisabled()) {
- iconDrawable.setState(FastBitmapDrawable.State.DISABLED);
- }
- setIcon(iconDrawable);
- if (info.contentDescription != null) {
- setContentDescription(info.contentDescription);
- }
- setText(info.title);
+ applyIconAndLabel(info.getIcon(iconCache), info);
setTag(info);
-
if (promiseStateChanged || info.isPromise()) {
applyState(promiseStateChanged);
}
}
public void applyFromApplicationInfo(AppInfo info) {
- FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(info.iconBitmap);
- if (info.isDisabled()) {
- iconDrawable.setState(FastBitmapDrawable.State.DISABLED);
- }
- setIcon(iconDrawable);
- setText(info.title);
- if (info.contentDescription != null) {
- setContentDescription(info.contentDescription);
- }
+ applyIconAndLabel(info.iconBitmap, info);
+
// We don't need to check the info since it's not a ShortcutInfo
super.setTag(info);
@@ -189,11 +171,7 @@
}
public void applyFromPackageItemInfo(PackageItemInfo info) {
- setIcon(mLauncher.createIconDrawable(info.iconBitmap));
- setText(info.title);
- if (info.contentDescription != null) {
- setContentDescription(info.contentDescription);
- }
+ applyIconAndLabel(info.iconBitmap, info);
// We don't need to check the info since it's not a ShortcutInfo
super.setTag(info);
@@ -201,6 +179,20 @@
verifyHighRes();
}
+ private void applyIconAndLabel(Bitmap icon, ItemInfo info) {
+ FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(icon);
+ if (info.isDisabled()) {
+ iconDrawable.setState(FastBitmapDrawable.State.DISABLED);
+ }
+ setIcon(iconDrawable);
+ setText(info.title);
+ if (info.contentDescription != null) {
+ setContentDescription(info.isDisabled()
+ ? getContext().getString(R.string.disabled_app_label, info.contentDescription)
+ : info.contentDescription);
+ }
+ }
+
/**
* Used for measurement only, sets some dummy values on this view.
*/
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 6755ff7..9030dae 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -918,10 +918,6 @@
bottom + mTempRect.bottom);
}
- public Rect getBackgroundBounds() {
- return mBackground.getBounds();
- }
-
/**
* Returns the amount of space left over after subtracting padding and cells. This space will be
* very small, a few pixels at most, and is a result of rounding down when calculating the cell
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 72bb343..2b130e5 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -296,7 +296,7 @@
}
public Point getTotalWorkspacePadding() {
- Rect padding = getWorkspacePadding();
+ Rect padding = getWorkspacePadding(null);
return new Point(padding.left + padding.right, padding.top + padding.bottom);
}
@@ -306,8 +306,8 @@
* this value is not reliable.
* Use {@link #getTotalWorkspacePadding()} instead.
*/
- public Rect getWorkspacePadding() {
- Rect padding = new Rect();
+ public Rect getWorkspacePadding(Rect recycle) {
+ Rect padding = recycle == null ? new Rect() : recycle;
if (isVerticalBarLayout()) {
// in case of isVerticalBarLayout, the hotseat is always on the right and the drop
// target bar is on the left, independent of the layout direction.
@@ -348,7 +348,7 @@
// In portrait, we want the pages spaced such that there is no
// overhang of the previous / next page into the current page viewport.
// We assume symmetrical padding in portrait mode.
- return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding().left);
+ return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding(null).left);
}
}
@@ -405,13 +405,15 @@
// Layout the workspace
PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
- lp = (FrameLayout.LayoutParams) workspace.getLayoutParams();
- lp.gravity = Gravity.CENTER;
- Rect padding = getWorkspacePadding();
- workspace.setLayoutParams(lp);
+ Rect padding = getWorkspacePadding(null);
workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
workspace.setPageSpacing(getWorkspacePageSpacing());
+ View qsbContainer = launcher.getQsbContainer();
+ lp = (FrameLayout.LayoutParams) qsbContainer.getLayoutParams();
+ lp.topMargin = padding.top;
+ qsbContainer.setLayoutParams(lp);
+
// Layout the hotseat
View hotseat = launcher.findViewById(R.id.hotseat);
lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 763daf4..b7f033e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -116,6 +116,7 @@
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.DeepShortcutsContainer;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
@@ -234,6 +235,7 @@
private View mLauncherView;
@Thunk DragLayer mDragLayer;
private DragController mDragController;
+ private View mQsbContainer;
public View mWeightWatcher;
@@ -1245,6 +1247,9 @@
// Close any open folders
closeFolder();
+ // Close any shortcuts containers
+ closeShortcutsContainer();
+
// Stop resizing any widgets
mWorkspace.exitWidgetResizeMode();
@@ -1329,6 +1334,8 @@
mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
+ mQsbContainer = mDragLayer.findViewById(mDeviceProfile.isVerticalBarLayout()
+ ? R.id.workspace_blocked_row : R.id.qsb_container);
mWorkspace.initParentViews(mDragLayer);
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -1779,6 +1786,10 @@
return mWorkspace;
}
+ public View getQsbContainer() {
+ return mQsbContainer;
+ }
+
public Hotseat getHotseat() {
return mHotseat;
}
@@ -1840,6 +1851,7 @@
mWorkspace.exitWidgetResizeMode();
closeFolder(alreadyOnHome);
+ closeShortcutsContainer();
exitSpringLoadedDragMode();
// If we are already on home, then just animate back to the workspace,
@@ -1927,6 +1939,8 @@
// TODO: Move folderInfo.isOpened out of the model and make it a UI state.
closeFolder(false);
+ closeShortcutsContainer();
+
if (mPendingAddInfo.container != ItemInfo.NO_ID && mPendingAddInfo.screenId > -1 &&
mWaitingForResult) {
ContentValues itemValues = new ContentValues();
@@ -2423,7 +2437,9 @@
return;
}
- if (isAppsViewVisible()) {
+ if (getOpenShortcutsContainer() != null) {
+ closeShortcutsContainer();
+ } else if (isAppsViewVisible()) {
showWorkspace(true);
} else if (isWidgetsViewVisible()) {
showOverviewMode(true);
@@ -3090,6 +3106,21 @@
getDragLayer().sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
+ public void closeShortcutsContainer() {
+ DeepShortcutsContainer deepShortcutsContainer = getOpenShortcutsContainer();
+ if (deepShortcutsContainer != null) {
+ mDragController.removeDragListener(deepShortcutsContainer);
+ mDragLayer.removeView(deepShortcutsContainer);
+ }
+ }
+
+ /**
+ * @return The open shortcuts container, or null if there is none
+ */
+ public DeepShortcutsContainer getOpenShortcutsContainer() {
+ return (DeepShortcutsContainer) mDragLayer.findViewById(R.id.deep_shortcuts_container);
+ }
+
@Override
public boolean onLongClick(View v) {
if (!isDraggingEnabled()) return false;
@@ -3351,6 +3382,7 @@
mUserPresent = false;
updateAutoAdvanceState();
closeFolder();
+ closeShortcutsContainer();
// Send an accessibility event to announce the context change
getWindow().getDecorView()
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 7c8bfab..ed1079f 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -30,7 +30,6 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews;
-import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
import java.util.ArrayList;
@@ -47,7 +46,6 @@
private Context mContext;
@ViewDebug.ExportedProperty(category = "launcher")
private int mPreviousOrientation;
- private DragLayer mDragLayer;
private float mSlop;
@@ -62,9 +60,7 @@
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mDragLayer = Launcher.getLauncher(context).getDragLayer();
setAccessibilityDelegate(Launcher.getLauncher(context).getAccessibilityDelegate());
-
setBackgroundResource(R.drawable.widget_internal_focus_bg);
}
@@ -117,7 +113,7 @@
if (!mStylusEventHelper.inStylusButtonPressed()) {
mLongPressHelper.postCheckForLongPress();
}
- mDragLayer.setTouchCompleteListener(this);
+ Launcher.getLauncher(getContext()).getDragLayer().setTouchCompleteListener(this);
break;
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 39e28c0..a75edb7 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -71,10 +71,10 @@
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.ManagedProfileHeuristic;
+import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.StringFilter;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -1942,7 +1942,16 @@
List<ShortcutInfoCompat> fullDetails = mDeepShortcutManager
.queryForFullDetails(packageName,
Collections.singletonList(shortcutId), user);
- if (fullDetails != null && !fullDetails.isEmpty()) {
+ if (fullDetails == null || fullDetails.isEmpty()) {
+ // There are no details for the shortcut. If this is due
+ // to a SecurityException, keep it in the database so
+ // we can restore the icon when the launcher regains
+ // permission. Otherwise remove the icon from the db.
+ if (!mDeepShortcutManager.wasLastCallSuccess()) {
+ itemsToRemove.add(id);
+ continue;
+ }
+ } else {
pinnedShortcut = fullDetails.get(0);
shouldPin = true;
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index a37fe5b..2758a7c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -145,9 +145,6 @@
protected int mActivePointerId = INVALID_POINTER;
- // If true, modify alpha of neighboring pages as user scrolls left/right
- protected boolean mFadeInAdjacentScreens = false;
-
protected boolean mIsPageMoving = false;
protected boolean mWasInOverscroll = false;
@@ -756,10 +753,6 @@
childWidth = getViewportWidth() - horizontalPadding
- mInsets.left - mInsets.right;
-
- if (lp.matchStartEdge) {
- childWidth += getPaddingStart();
- }
childHeight = getViewportHeight() - verticalPadding
- mInsets.top - mInsets.bottom;
mNormalChildHeight = childHeight;
@@ -809,8 +802,7 @@
LayoutParams lp = (LayoutParams) getChildAt(startIndex).getLayoutParams();
LayoutParams nextLp;
- int childLeft = offsetX +
- ((lp.isFullScreenPage || (!mIsRtl && lp.matchStartEdge)) ? 0 : getPaddingLeft());
+ int childLeft = offsetX + (lp.isFullScreenPage ? 0 : getPaddingLeft());
if (mPageScrolls == null || childCount != mChildCountOnLastLayout) {
mPageScrolls = new int[childCount];
}
@@ -834,8 +826,7 @@
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(), childTop + childHeight);
- int scrollOffsetLeft = (lp.isFullScreenPage || (!mIsRtl & lp.matchStartEdge)) ?
- 0 : getPaddingLeft();
+ int scrollOffsetLeft = lp.isFullScreenPage ? 0 : getPaddingLeft();
mPageScrolls[i] = childLeft - scrollOffsetLeft - offsetX;
int pageGap = mPageSpacing;
diff --git a/src/com/android/launcher3/PinchAnimationManager.java b/src/com/android/launcher3/PinchAnimationManager.java
index c1c2519..3807945 100644
--- a/src/com/android/launcher3/PinchAnimationManager.java
+++ b/src/com/android/launcher3/PinchAnimationManager.java
@@ -51,8 +51,8 @@
private static final int THRESHOLD_ANIM_DURATION = 150;
private static final LinearInterpolator INTERPOLATOR = new LinearInterpolator();
- private static final int INDEX_PAGE_INDICATOR = 0;
- private static final int INDEX_HOTSEAT = 1;
+ private static final int INDEX_HOTSEAT = 0;
+ private static final int INDEX_QSB = 1;
private static final int INDEX_OVERVIEW_PANEL_BUTTONS = 2;
private static final int INDEX_SCRIM = 3;
@@ -189,11 +189,10 @@
}
private void animateHotseatAndPageIndicator(boolean show) {
- animateShowHideView(INDEX_HOTSEAT, mLauncher.getHotseat(), show);
- if (mWorkspace.getPageIndicator() != null) {
- // There aren't page indicators in landscape mode on phones, hence the null check.
- animateShowHideView(INDEX_PAGE_INDICATOR, mWorkspace.getPageIndicator(), show);
- }
+ startAnimator(INDEX_HOTSEAT,
+ mWorkspace.createHotseatAlphaAnimator(show ? 1 : 0), THRESHOLD_ANIM_DURATION);
+ startAnimator(INDEX_QSB, mWorkspace.mQsbAlphaController.animateAlphaAtIndex(
+ show ? 1 : 0, Workspace.QSB_ALPHA_INDEX_STATE_CHANGE), THRESHOLD_ANIM_DURATION);
}
private void animateOverviewPanelButtons(boolean show) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 1b3f5df..8d46719 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -53,9 +53,11 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
+import android.widget.Space;
import android.widget.TextView;
import com.android.launcher3.Launcher.CustomContentCallbacks;
@@ -82,6 +84,7 @@
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.MultiStateAlphaController;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperOffsetInterpolator;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -227,6 +230,12 @@
*/
private float[] mHotseatAlpha = new float[] {1, 1, 1};
+ public static final int QSB_ALPHA_INDEX_STATE_CHANGE = 0;
+ public static final int QSB_ALPHA_INDEX_Y_TRANSLATION = 1;
+ public static final int QSB_ALPHA_INDEX_PAGE_SCROLL = 2;
+
+ MultiStateAlphaController mQsbAlphaController;
+
@ViewDebug.ExportedProperty(category = "launcher")
private State mState = State.NORMAL;
private boolean mIsSwitchingState = false;
@@ -305,6 +314,7 @@
private boolean mForceDrawAdjacentPages = false;
// Total over scrollX in the overlay direction.
private float mOverlayTranslation;
+ private int mFirstPageScrollX;
// Handles workspace state transitions
private WorkspaceStateTransitionAnimation mStateTransitionAnimation;
@@ -339,7 +349,6 @@
final Resources res = getResources();
DeviceProfile grid = mLauncher.getDeviceProfile();
mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
- mFadeInAdjacentScreens = false;
mWallpaperManager = WallpaperManager.getInstance(context);
mWallpaperOffset = new WallpaperOffsetInterpolator(this);
@@ -484,6 +493,7 @@
public void initParentViews(View parent) {
super.initParentViews(parent);
mPageIndicator.setAccessibilityDelegate(new OverviewAccessibilityDelegate());
+ mQsbAlphaController = new MultiStateAlphaController(mLauncher.getQsbContainer(), 3);
}
private int getDefaultPage() {
@@ -548,6 +558,11 @@
return mTouchState != TOUCH_STATE_REST;
}
+ private int getEmbeddedQsbId() {
+ return mLauncher.getDeviceProfile().isVerticalBarLayout()
+ ? R.id.qsb_container : R.id.workspace_blocked_row;
+ }
+
/**
* Initializes and binds the first page
* @param qsb an exisitng qsb to recycle or null.
@@ -559,31 +574,45 @@
// Add the first page
CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
- if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- // Let the cell layout extend the start padding. On transposed layout, there is page
- // indicator on left and hotseat on right, as such workspace does not touch the edge.
- ((LayoutParams) firstPage.getLayoutParams()).matchStartEdge = true;
- firstPage.setPaddingRelative(getPaddingStart(), 0, 0, 0);
- }
-
+ // Always add a QSB on the first screen.
if (qsb == null) {
- // Always add a QSB on the first screen.
- qsb = mLauncher.getLayoutInflater().inflate(R.layout.qsb_container,
- firstPage, false);
+ // In transposed layout, we add the QSB in the Grid. As workspace does not touch the
+ // edges, we do not need a full width QSB.
+ if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ qsb = mLauncher.getLayoutInflater().inflate(R.layout.qsb_container, firstPage, false);
+ } else {
+ qsb = new Space(getContext());
+ }
}
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) qsb.getLayoutParams();
- lp.cellX = 0;
- lp.cellY = 0;
- lp.cellHSpan = firstPage.getCountX();
- lp.cellVSpan = 1;
+ CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1);
lp.canReorder = false;
-
- if (!firstPage.addViewToCellLayout(qsb, 0, R.id.qsb_container, lp, true)) {
+ if (!firstPage.addViewToCellLayout(qsb, 0, getEmbeddedQsbId(), lp, true)) {
Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout");
}
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ // Update the QSB to match the cell height. This is treating the QSB essentially as a child
+ // of workspace despite that it's not a true child.
+ // Note that it relies on the strict ordering of measuring the workspace before the QSB
+ // at the dragLayer level.
+ if (getChildCount() > 0) {
+ CellLayout firstPage = (CellLayout) getChildAt(0);
+ int cellHeight = firstPage.getCellHeight();
+
+ View qsbContainer = mLauncher.getQsbContainer();
+ ViewGroup.LayoutParams lp = qsbContainer.getLayoutParams();
+ if (cellHeight > 0 && lp.height != cellHeight) {
+ lp.height = cellHeight;
+ }
+ qsbContainer.setLayoutParams(lp);
+ }
+ }
+
public void removeAllWorkspaceScreens() {
// Disable all layout transitions before removing all pages to ensure that we don't get the
// transition animations competing with us changing the scroll when we add pages or the
@@ -597,7 +626,7 @@
}
// Recycle the QSB widget
- View qsb = findViewById(R.id.qsb_container);
+ View qsb = findViewById(getEmbeddedQsbId());
if (qsb != null) {
((ViewGroup) qsb.getParent()).removeView(qsb);
}
@@ -1366,9 +1395,15 @@
super.scrollTo(x, y);
}
+ private void onWorkspaceOverallScrollChanged() {
+ mLauncher.getQsbContainer().setTranslationX(
+ mOverlayTranslation + mFirstPageScrollX - getScrollX());
+ }
+
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
+ onWorkspaceOverallScrollChanged();
// Update the page indicator progress.
boolean isTransitioning = mIsSwitchingState
@@ -1438,6 +1473,19 @@
// device I've tried, translating the launcher causes things to get quite laggy.
setWorkspaceTranslationAndAlpha(Direction.X, transX, alpha);
setHotseatTranslationAndAlpha(Direction.X, transX, alpha);
+ onWorkspaceOverallScrollChanged();
+ }
+
+ /**
+ * Moves the workspace UI in the Y direction.
+ * @param translation the amount of shift.
+ * @param alpha the alpha for the workspace page
+ */
+ public void setWorkspaceYTranslationAndAlpha(float translation, float alpha) {
+ setWorkspaceTranslationAndAlpha(Direction.Y, translation, alpha);
+
+ mLauncher.getQsbContainer().setTranslationY(translation);
+ mQsbAlphaController.setAlphaAtIndex(alpha, QSB_ALPHA_INDEX_Y_TRANSLATION);
}
/**
@@ -1446,7 +1494,7 @@
* @param translation the amount of shift.
* @param alpha the alpha for the workspace page
*/
- public void setWorkspaceTranslationAndAlpha(Direction direction, float translation, float alpha) {
+ private void setWorkspaceTranslationAndAlpha(Direction direction, float translation, float alpha) {
Property<View, Float> property = direction.viewProperty;
mPageAlpha[direction.ordinal()] = alpha;
float finalAlpha = mPageAlpha[0] * mPageAlpha[1];
@@ -1630,6 +1678,10 @@
float scrollProgress = getScrollProgress(screenCenter, child, i);
float alpha = 1 - Math.abs(scrollProgress);
child.getShortcutsAndWidgets().setAlpha(alpha);
+
+ if (isQsbContainerPage(i)) {
+ mQsbAlphaController.setAlphaAtIndex(alpha, QSB_ALPHA_INDEX_PAGE_SCROLL);
+ }
}
}
}
@@ -1751,6 +1803,8 @@
mWallpaperOffset.jumpToFinal();
}
super.onLayout(changed, left, top, right, bottom);
+ mFirstPageScrollX = getScrollForPage(0);
+ onWorkspaceOverallScrollChanged();
}
@Override
@@ -2027,10 +2081,10 @@
int getOverviewModeTranslationY() {
DeviceProfile grid = mLauncher.getDeviceProfile();
- Rect workspacePadding = grid.getWorkspacePadding();
int overviewButtonBarHeight = grid.getOverviewModeButtonBarHeight();
int scaledHeight = (int) (mOverviewModeShrinkFactor * getNormalChildHeight());
+ Rect workspacePadding = grid.getWorkspacePadding(sTempRect);
int workspaceTop = mInsets.top + workspacePadding.top;
int workspaceBottom = getViewportHeight() - mInsets.bottom - workspacePadding.bottom;
int overviewTop = mInsets.top;
@@ -2045,12 +2099,12 @@
if (grid.isVerticalBarLayout() || getChildCount() == 0) {
return 0;
}
- Rect workspacePadding = grid.getWorkspacePadding();
float scaledHeight = grid.workspaceSpringLoadShrinkFactor * getNormalChildHeight();
float shrunkTop = mInsets.top + grid.dropTargetBarSizePx;
float shrunkBottom = getViewportHeight() - mInsets.bottom
- - workspacePadding.bottom - grid.workspaceSpringLoadedBottomSpace;
+ - grid.getWorkspacePadding(sTempRect).bottom
+ - grid.workspaceSpringLoadedBottomSpace;
float totalShrunkSpace = shrunkBottom - shrunkTop;
float desiredCellTop = shrunkTop + (totalShrunkSpace - scaledHeight) / 2;
@@ -4523,4 +4577,8 @@
*/
void prepareStateChange(State toState, AnimatorSet targetAnim);
}
+
+ public static final boolean isQsbContainerPage(int pageNo) {
+ return pageNo == 0;
+ }
}
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index a73f3ec..c2631b0 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -276,6 +276,8 @@
float finalHotseatAlpha = (states.stateIsNormal || states.stateIsSpringLoaded ||
(FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f;
float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f;
+ float finalQsbAlpha = (states.stateIsNormal ||
+ (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f;
float finalWorkspaceTranslationY = 0;
if (states.stateIsOverview || states.stateIsOverviewHidden) {
@@ -355,9 +357,28 @@
cl.setBackgroundAlpha(finalBackgroundAlpha);
cl.setShortcutAndWidgetAlpha(finalAlpha);
}
+
+ if (Workspace.isQsbContainerPage(i)) {
+ if (animated) {
+ Animator anim = mWorkspace.mQsbAlphaController
+ .animateAlphaAtIndex(finalAlpha, Workspace.QSB_ALPHA_INDEX_PAGE_SCROLL);
+ anim.setDuration(duration);
+ anim.setInterpolator(mZoomInInterpolator);
+ mStateAnimator.play(anim);
+ } else {
+ mWorkspace.mQsbAlphaController.setAlphaAtIndex(
+ finalAlpha, Workspace.QSB_ALPHA_INDEX_PAGE_SCROLL);
+ }
+ }
}
final ViewGroup overviewPanel = mLauncher.getOverviewPanel();
+
+ final View qsbContainer = mLauncher.getQsbContainer();
+
+ Animator qsbAlphaAnimation = mWorkspace.mQsbAlphaController
+ .animateAlphaAtIndex(finalQsbAlpha, Workspace.QSB_ALPHA_INDEX_STATE_CHANGE);
+
if (animated) {
LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(mWorkspace);
scale.scaleX(mNewScale)
@@ -376,10 +397,13 @@
// For animation optimations, we may need to provide the Launcher transition
// with a set of views on which to force build layers in certain scenarios.
overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ qsbContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
if (layerViews != null) {
// If layerViews is not null, we add these views, and indicate that
// the caller can manage layer state.
layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+ layerViews.put(qsbContainer, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+
layerViews.put(mLauncher.getHotseat(),
LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
layerViews.put(mWorkspace.getPageIndicator(),
@@ -399,9 +423,11 @@
overviewPanelAlpha.setDuration(duration);
hotseatAlpha.setDuration(duration);
+ qsbAlphaAnimation.setDuration(duration);
mStateAnimator.play(overviewPanelAlpha);
mStateAnimator.play(hotseatAlpha);
+ mStateAnimator.play(qsbAlphaAnimation);
mStateAnimator.addListener(new AnimatorListenerAdapter() {
boolean canceled = false;
@Override
@@ -422,6 +448,8 @@
} else {
overviewPanel.setAlpha(finalOverviewPanelAlpha);
AlphaUpdateListener.updateVisibility(overviewPanel, accessibilityEnabled);
+
+ qsbAlphaAnimation.end();
mWorkspace.createHotseatAlphaAnimator(finalHotseatAlpha).end();
mWorkspace.updateCustomContentVisibility();
mWorkspace.setScaleX(mNewScale);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 028f065..e7108a1 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -291,7 +291,7 @@
mDecelInterpolator.getInterpolation(alpha))));
mAppsView.getContentView().setAlpha(alpha);
mAppsView.setTranslationY(progress);
- mWorkspace.setWorkspaceTranslationAndAlpha(Direction.Y,
+ mWorkspace.setWorkspaceYTranslationAndAlpha(
PARALLAX_COEFFICIENT * (-mShiftRange + progress),
mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index ce97536..5f8faab 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -231,8 +231,7 @@
}
// Remove the shortcuts container when touching outside of it.
- DeepShortcutsContainer deepShortcutsContainer = (DeepShortcutsContainer)
- findViewById(R.id.deep_shortcuts_container);
+ DeepShortcutsContainer deepShortcutsContainer = mLauncher.getOpenShortcutsContainer();
if (deepShortcutsContainer != null) {
if (isEventOverView(deepShortcutsContainer, ev)) {
// Let the container handle the event.
@@ -244,7 +243,7 @@
return true;
}
} else {
- removeView(deepShortcutsContainer);
+ mLauncher.closeShortcutsContainer();
// We let touches on the original icon go through so that users can launch
// the app with one tap if they don't find a shortcut they want.
return !isEventOverView(deepShortcutsContainer.getDeferredDragIcon(), ev);
@@ -547,10 +546,6 @@
return new LayoutParams(p);
}
- public void setController(TouchController controller) {
- mActiveController = controller;
- }
-
public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
public int x, y;
public boolean customPosition = false;
@@ -752,13 +747,14 @@
* location doesn't account for scaling, and so should be centered about the desired
* final location (including scaling).
* @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
- * @param finalScale The final scale of the view. The view is scaled about its center.
+ * @param finalScaleX The final scale of the view. The view is scaled about its center.
+ * @param finalScaleY The final scale of the view. The view is scaled about its center.
* @param duration The duration of the animation.
* @param motionInterpolator The interpolator to use for the location of the view.
* @param alphaInterpolator The interpolator to use for the alpha of the view.
* @param onCompleteRunnable Optional runnable to run on animation completion.
- * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
- * the runnable will execute after the view is faded out.
+ * @param animationEndStyle Whether or not to fade out the view once the animation completes.
+ * {@link #ANIMATION_END_DISAPPEAR} or {@link #ANIMATION_END_REMAIN_VISIBLE}.
* @param anchorView If not null, this represents the view which the animated view stays
* anchored to in case scrolling is currently taking place. Note: currently this is
* only used for the X dimension for the case of the workspace.
@@ -993,12 +989,7 @@
canvas.save();
if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
// Cut a hole in the darkening scrim on the page that should be highlighted, if any.
- float scale = getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
- Rect backBounds = currCellLayout.getBackgroundBounds();
- mHighlightRect.left += (int) (backBounds.left * scale);
- mHighlightRect.top += (int) (backBounds.top * scale);
- mHighlightRect.right = (int) (mHighlightRect.left + backBounds.width() * scale);
- mHighlightRect.bottom = (int) (mHighlightRect.top + backBounds.height() * scale);
+ getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
}
canvas.drawColor((alpha << 24) | SCRIM_COLOR);
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
index 8bceda7..66e98cd 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -25,7 +25,6 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.UserHandle;
import android.util.Log;
import com.android.launcher3.ItemInfo;
@@ -33,7 +32,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.UserHandleCompat;
-import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -53,14 +51,18 @@
FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST;
private final LauncherApps mLauncherApps;
+ private boolean mWasLastCallSuccess;
public DeepShortcutManager(Context context, ShortcutCache shortcutCache) {
mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
}
public static boolean supportsShortcuts(ItemInfo info) {
- return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+ return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+ }
+
+ public boolean wasLastCallSuccess() {
+ return mWasLastCallSuccess;
}
public void onShortcutsChanged(List<ShortcutInfoCompat> shortcuts) {
@@ -100,8 +102,10 @@
pinnedIds.remove(id);
try {
mLauncherApps.pinShortcuts(packageName, pinnedIds, user.getUser());
+ mWasLastCallSuccess = true;
} catch (SecurityException e) {
- Log.e(TAG, Log.getStackTraceString(e));
+ Log.w(TAG, "Failed to unpin shortcut", e);
+ mWasLastCallSuccess = false;
}
}
}
@@ -120,8 +124,10 @@
pinnedIds.add(id);
try {
mLauncherApps.pinShortcuts(packageName, pinnedIds, user.getUser());
+ mWasLastCallSuccess = true;
} catch (SecurityException e) {
- Log.e(TAG, Log.getStackTraceString(e));
+ Log.w(TAG, "Failed to pin shortcut", e);
+ mWasLastCallSuccess = false;
}
}
}
@@ -131,16 +137,12 @@
Bundle startActivityOptions, UserHandleCompat user) {
if (Utilities.isNycMR1OrAbove()) {
try {
- // TODO: remove reflection once updated SDK is ready.
- // mLauncherApps.startShortcut(packageName, id, sourceBounds,
- // startActivityOptions, user.getUser());
- mLauncherApps.getClass().getMethod("startShortcut", String.class, String.class,
- Rect.class, Bundle.class, UserHandle.class).invoke(mLauncherApps,
- packageName, id, sourceBounds, startActivityOptions, user.getUser());
+ mLauncherApps.startShortcut(packageName, id, sourceBounds,
+ startActivityOptions, user.getUser());
+ mWasLastCallSuccess = true;
} catch (SecurityException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
- e.printStackTrace();
+ Log.e(TAG, "Failed to start shortcut", e);
+ mWasLastCallSuccess = false;
}
}
}
@@ -149,10 +151,13 @@
public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
if (Utilities.isNycMR1OrAbove()) {
try {
- return mLauncherApps.getShortcutIconDrawable(shortcutInfo.getShortcutInfo(),
- density);
+ Drawable icon = mLauncherApps.getShortcutIconDrawable(
+ shortcutInfo.getShortcutInfo(), density);
+ mWasLastCallSuccess = true;
+ return icon;
} catch (SecurityException e) {
- Log.e(TAG, Log.getStackTraceString(e));
+ Log.e(TAG, "Failed to get shortcut icon", e);
+ mWasLastCallSuccess = false;
}
}
return null;
@@ -200,8 +205,10 @@
List<ShortcutInfo> shortcutInfos = null;
try {
shortcutInfos = mLauncherApps.getShortcuts(q, user.getUser());
+ mWasLastCallSuccess = true;
} catch (SecurityException e) {
- Log.e(TAG, Log.getStackTraceString(e));
+ Log.e(TAG, "Failed to query for shortcuts", e);
+ mWasLastCallSuccess = false;
}
if (shortcutInfos == null) {
return Collections.EMPTY_LIST;
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index 6f3875c..d9e34a6 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -7,8 +7,10 @@
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.AsyncTask;
import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -21,30 +23,30 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
import com.android.launcher3.LogDecelerateInterpolator;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadCircularReveal;
-import java.util.ArrayList;
import java.util.List;
/**
* A container for shortcuts to deep links within apps.
*/
@TargetApi(Build.VERSION_CODES.N)
-public class DeepShortcutsContainer extends LinearLayout implements View.OnClickListener,
- View.OnLongClickListener, View.OnTouchListener, DragSource,
- UserEventDispatcher.LaunchSourceProvider, TouchController {
+public class DeepShortcutsContainer extends LinearLayout implements View.OnLongClickListener,
+ View.OnTouchListener, DragSource, DragController.DragListener,
+ UserEventDispatcher.LaunchSourceProvider {
private static final String TAG = "ShortcutsContainer";
private Launcher mLauncher;
@@ -98,37 +100,53 @@
deferDrag(originalIcon);
// Load the shortcuts on a background thread and update the container as it animates.
+ final Looper workerLooper = LauncherModel.getWorkerLooper();
+ final Handler uiHandler = new Handler(Looper.getMainLooper());
final ItemInfo originalInfo = (ItemInfo) originalIcon.getTag();
final UserHandleCompat user = originalInfo.user;
final ComponentName activity = originalInfo.getTargetComponent();
- new AsyncTask<Void, Void, List<ShortcutInfo>>() {
- public List<ShortcutInfo> doInBackground(Void ... args) {
- List<ShortcutInfoCompat> shortcuts = mDeepShortcutsManager
- .queryForAllAppShortcuts(activity, ids, user);
- List<ShortcutInfo> shortcutInfos = new ArrayList<>(shortcuts.size());
- for (ShortcutInfoCompat shortcut : shortcuts) {
- shortcutInfos.add(ShortcutInfo.fromDeepShortcutInfo(shortcut, mLauncher));
- }
- return shortcutInfos;
- }
-
- // TODO: implement onProgressUpdate() to load shortcuts one at a time.
-
+ new Handler(workerLooper).postAtFrontOfQueue(new Runnable() {
@Override
- protected void onPostExecute(List<ShortcutInfo> shortcuts) {
+ public void run() {
+ final List<ShortcutInfoCompat> shortcuts = mDeepShortcutsManager
+ .queryForAllAppShortcuts(activity, ids, user);
for (int i = 0; i < shortcuts.size(); i++) {
- DeepShortcutView iconAndText = (DeepShortcutView) getChildAt(i);
- ShortcutInfo launcherShortcutInfo = shortcuts.get(i);
- iconAndText.applyFromShortcutInfo(launcherShortcutInfo,
- LauncherAppState.getInstance().getIconCache());
- iconAndText.setOnClickListener(DeepShortcutsContainer.this);
- iconAndText.setOnLongClickListener(DeepShortcutsContainer.this);
- iconAndText.setOnTouchListener(DeepShortcutsContainer.this);
- int viewId = mLauncher.getViewIdForItem(originalInfo);
- iconAndText.setId(viewId);
+ final ShortcutInfoCompat shortcut = shortcuts.get(i);
+ final ShortcutInfo launcherShortcutInfo = ShortcutInfo
+ .fromDeepShortcutInfo(shortcut, mLauncher);
+ CharSequence label = shortcut.getLongLabel();
+ if (TextUtils.isEmpty(label)) {
+ label = shortcut.getShortLabel();
+ }
+ uiHandler.post(new UpdateShortcutChild(i, launcherShortcutInfo, label));
}
}
- }.execute();
+ });
+ }
+
+ /** Updates the child of this container at the given index based on the given shortcut info. */
+ private class UpdateShortcutChild implements Runnable {
+ private int mShortcutChildIndex;
+ private ShortcutInfo mShortcutChildInfo;
+ private CharSequence mLabel;
+
+ public UpdateShortcutChild(int shortcutChildIndex, ShortcutInfo shortcutChildInfo,
+ CharSequence label) {
+ mShortcutChildIndex = shortcutChildIndex;
+ mShortcutChildInfo = shortcutChildInfo;
+ mLabel = label;
+ }
+
+ @Override
+ public void run() {
+ DeepShortcutView shortcutView = (DeepShortcutView) getChildAt(mShortcutChildIndex);
+ shortcutView.applyFromShortcutInfo(mShortcutChildInfo,
+ LauncherAppState.getInstance().getIconCache());
+ shortcutView.setText(mLabel);
+ shortcutView.setOnClickListener(mLauncher);
+ shortcutView.setOnLongClickListener(DeepShortcutsContainer.this);
+ shortcutView.setOnTouchListener(DeepShortcutsContainer.this);
+ }
}
// TODO: update this animation
@@ -194,6 +212,7 @@
private void deferDrag(BubbleTextView originalIcon) {
mDeferredDragIcon = originalIcon;
showDragView(originalIcon);
+ mLauncher.getDragController().addDragListener(this);
}
public BubbleTextView getDeferredDragIcon() {
@@ -219,9 +238,9 @@
mDragView.show(motionDownX, motionDownY);
}
- public boolean onForwardedEvent(MotionEvent ev, int activePointerId, MotionEvent touchDownEvent) {
- mTouchDown = new Point((int) touchDownEvent.getX(), (int) touchDownEvent.getY());
+ public boolean onForwardedEvent(MotionEvent ev, int activePointerId, Point touchDown) {
mActivePointerId = activePointerId;
+ mTouchDown = touchDown;
return dispatchTouchEvent(ev);
}
@@ -231,7 +250,6 @@
return false;
}
-
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
if (activePointerIndex < 0) {
return false;
@@ -256,12 +274,10 @@
boolean containerContainsTouch = x >= 0 && y >= 0 && x < getWidth() && y < getHeight();
if (shouldStartDeferredDrag((int) x, (int) y, containerContainsTouch)) {
- mDeferredDragIcon.getParent().requestDisallowInterceptTouchEvent(false);
- mDeferredDragIcon.setVisibility(VISIBLE);
- mDeferredDragIcon.getOnLongClickListener().onLongClick(mDeferredDragIcon);
- mLauncher.getDragLayer().removeView(this);
- mLauncher.getDragController().onTouchEvent(ev);
cleanupDeferredDrag();
+ mDeferredDragIcon.getParent().requestDisallowInterceptTouchEvent(false);
+ mDeferredDragIcon.getOnLongClickListener().onLongClick(mDeferredDragIcon);
+ mLauncher.getDragController().onTouchEvent(ev);
return true;
} else {
// Determine whether touch is over a shortcut.
@@ -288,7 +304,6 @@
}
}
} else if (action == MotionEvent.ACTION_UP) {
- mDeferredDragIcon.setVisibility(VISIBLE);
cleanupDeferredDrag();
// Launch a shortcut if user was hovering over it.
for (int i = 0; i < childCount; i++) {
@@ -316,9 +331,9 @@
* @param y the y touch coordinate relative to this container
*/
private boolean shouldStartDeferredDrag(int x, int y, boolean containerContainsTouch) {
- Point closestEdge = new Point(mTouchDown.x, mIsAboveIcon ? getMeasuredHeight() : 0);
- double distToEdge = Math.hypot(mTouchDown.x - closestEdge.x, mTouchDown.y - closestEdge.y);
- double newDistToEdge = Math.hypot(x - closestEdge.x, y - closestEdge.y);
+ int closestEdgeY = mIsAboveIcon ? getMeasuredHeight() : 0;
+ double distToEdge = Math.abs(mTouchDown.y - closestEdgeY);
+ double newDistToEdge = Math.hypot(x - mTouchDown.x, y - closestEdgeY);
return !containerContainsTouch && (newDistToEdge - distToEdge > mStartDragThreshold);
}
@@ -326,6 +341,7 @@
if (mDragView != null) {
mDragView.remove();
}
+ mDeferredDragIcon.setVisibility(VISIBLE);
}
@Override
@@ -340,13 +356,6 @@
return false;
}
- @Override
- public void onClick(View view) {
- // Clicked on a shortcut.
- mLauncher.onClick(view);
- ((DragLayer) getParent()).removeView(this);
- }
-
public boolean onLongClick(View v) {
// Return early if this is not initiated from a touch
if (!v.isInTouchMode()) return false;
@@ -354,11 +363,7 @@
if (!mLauncher.isDraggingEnabled()) return false;
// Long clicked on a shortcut.
- // TODO remove this hack; it required because DragLayer isn't intercepting touch, so
- // the controller is not updated from what it was previously.
- mLauncher.getDragLayer().setController(mLauncher.getDragController());
mLauncher.getWorkspace().beginDragShared(v, mIconLastTouchPos, this, false);
- ((DragLayer) getParent()).removeView(this);
// TODO: support dragging from within folder without having to close it
mLauncher.closeFolder();
return false;
@@ -401,6 +406,19 @@
}
@Override
+ public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+ // Either the original icon or one of the shortcuts was dragged.
+ // Hide the container, but don't remove it yet because that interferes with touch events.
+ setVisibility(INVISIBLE);
+ }
+
+ @Override
+ public void onDragEnd() {
+ // Now remove the container.
+ mLauncher.closeShortcutsContainer();
+ }
+
+ @Override
public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
target.itemType = LauncherLogProto.SHORTCUT; // TODO: change to DYNAMIC_SHORTCUT
target.gridX = info.cellX;
diff --git a/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java b/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java
index 956623e..63c8363 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java
@@ -1,6 +1,7 @@
package com.android.launcher3.shortcuts;
import android.content.Context;
+import android.graphics.Point;
import android.os.SystemClock;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
@@ -53,6 +54,8 @@
private Launcher mLauncher;
private DragLayer mDragLayer;
private MotionEvent mTouchDownEvent;
+ /** The coordinates of the touch down, relative do the shortcuts container. */
+ private final Point mTouchDown;
public ShortcutsContainerListener(BubbleTextView icon) {
mSrcIcon = icon;
@@ -64,8 +67,8 @@
icon.addOnAttachStateChangeListener(this);
mLauncher = Launcher.getLauncher(mSrcIcon.getContext());
-
mDragLayer = mLauncher.getDragLayer();
+ mTouchDown = new Point();
}
@Override
@@ -76,6 +79,9 @@
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mTouchDownEvent != null) {
+ mTouchDownEvent.recycle();
+ }
mTouchDownEvent = MotionEvent.obtainNoHistory(event);
}
@@ -134,6 +140,10 @@
deepShortcutsContainer.populateAndShow(mSrcIcon, ids);
mSrcIcon.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+
+ // Convert touch down event to the container's coordinates.
+ Utilities.translateEventCoordinates(mSrcIcon, deepShortcutsContainer, mTouchDownEvent);
+ mTouchDown.set((int) mTouchDownEvent.getX(), (int) mTouchDownEvent.getY());
return true;
}
return false;
@@ -243,8 +253,7 @@
private boolean onTouchForwarded(MotionEvent srcEvent) {
final View src = mSrcIcon;
- final DeepShortcutsContainer dst = (DeepShortcutsContainer)
- mDragLayer.findViewById(R.id.deep_shortcuts_container);
+ final DeepShortcutsContainer dst = mLauncher.getOpenShortcutsContainer();
if (dst == null) {
return false;
}
@@ -253,16 +262,10 @@
final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
Utilities.translateEventCoordinates(src, dst, dstEvent);
- // Convert touch down event to destination-local coordinates.
- // TODO: only create this once, or just store the x and y.
- final MotionEvent touchDownEvent = MotionEvent.obtainNoHistory(mTouchDownEvent);
- Utilities.translateEventCoordinates(src, dst, touchDownEvent);
-
// Forward converted event to destination view, then recycle it.
// TODO: don't create objects in onForwardedEvent.
- final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId, touchDownEvent);
+ final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId, mTouchDown);
dstEvent.recycle();
- touchDownEvent.recycle();
// Always cancel forwarding when the touch stream ends.
final int action = srcEvent.getActionMasked();
diff --git a/src/com/android/launcher3/util/MultiStateAlphaController.java b/src/com/android/launcher3/util/MultiStateAlphaController.java
new file mode 100644
index 0000000..df73bfd
--- /dev/null
+++ b/src/com/android/launcher3/util/MultiStateAlphaController.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 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.util;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+
+import java.util.Arrays;
+
+/**
+ * A utility class which divides the alpha for a view across multiple states.
+ */
+public class MultiStateAlphaController {
+
+ private final View mTargetView;
+ private final float[] mAlphas;
+ private final AccessibilityManager mAm;
+
+ public MultiStateAlphaController(View view, int stateCount) {
+ mTargetView = view;
+ mAlphas = new float[stateCount];
+ Arrays.fill(mAlphas, 1);
+
+ mAm = (AccessibilityManager) view.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+ }
+
+ public void setAlphaAtIndex(float alpha, int index) {
+ mAlphas[index] = alpha;
+ float finalAlpha = 1;
+ for (float a : mAlphas) {
+ finalAlpha = finalAlpha * a;
+ }
+ mTargetView.setAlpha(finalAlpha);
+ mTargetView.setVisibility(alpha > 0 ? View.VISIBLE
+ : (mAm.isEnabled() ? View.GONE : View.INVISIBLE));
+ }
+
+ public Animator animateAlphaAtIndex(float finalAlpha, final int index) {
+ if (Float.compare(finalAlpha, mAlphas[index]) == 0) {
+ // Return a dummy animator to avoid null checks.
+ return ValueAnimator.ofFloat(0, 0);
+ } else {
+ ValueAnimator animator = ValueAnimator.ofFloat(mAlphas[index], finalAlpha);
+ animator.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ float value = (Float) valueAnimator.getAnimatedValue();
+ setAlphaAtIndex(value, index);
+ }
+ });
+ return animator;
+ }
+ }
+}