Merge "Refactoring deferred bind logic" into ub-launcher3-master
diff --git a/res/drawable-hdpi/page_hover_left.9.png b/res/drawable-hdpi/page_hover_left.9.png
deleted file mode 100644
index 3f11d0b..0000000
--- a/res/drawable-hdpi/page_hover_left.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_left_active.9.png b/res/drawable-hdpi/page_hover_left_active.9.png
deleted file mode 100644
index abe4c31..0000000
--- a/res/drawable-hdpi/page_hover_left_active.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_right.9.png b/res/drawable-hdpi/page_hover_right.9.png
deleted file mode 100644
index 3bcf191..0000000
--- a/res/drawable-hdpi/page_hover_right.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_right_active.9.png b/res/drawable-hdpi/page_hover_right_active.9.png
deleted file mode 100644
index 101e4dc..0000000
--- a/res/drawable-hdpi/page_hover_right_active.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_left.9.png b/res/drawable-mdpi/page_hover_left.9.png
deleted file mode 100644
index 2b6094c..0000000
--- a/res/drawable-mdpi/page_hover_left.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_left_active.9.png b/res/drawable-mdpi/page_hover_left_active.9.png
deleted file mode 100644
index 9eb00a2..0000000
--- a/res/drawable-mdpi/page_hover_left_active.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_right.9.png b/res/drawable-mdpi/page_hover_right.9.png
deleted file mode 100644
index c2e59835..0000000
--- a/res/drawable-mdpi/page_hover_right.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_right_active.9.png b/res/drawable-mdpi/page_hover_right_active.9.png
deleted file mode 100644
index d2771a1..0000000
--- a/res/drawable-mdpi/page_hover_right_active.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_left.9.png b/res/drawable-xhdpi/page_hover_left.9.png
deleted file mode 100644
index dbcc0ab..0000000
--- a/res/drawable-xhdpi/page_hover_left.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_left_active.9.png b/res/drawable-xhdpi/page_hover_left_active.9.png
deleted file mode 100644
index 3233efe..0000000
--- a/res/drawable-xhdpi/page_hover_left_active.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_right.9.png b/res/drawable-xhdpi/page_hover_right.9.png
deleted file mode 100644
index d82f809..0000000
--- a/res/drawable-xhdpi/page_hover_right.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_right_active.9.png b/res/drawable-xhdpi/page_hover_right_active.9.png
deleted file mode 100644
index 819ea19..0000000
--- a/res/drawable-xhdpi/page_hover_right_active.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_left.9.png b/res/drawable-xxhdpi/page_hover_left.9.png
deleted file mode 100644
index c81f86c..0000000
--- a/res/drawable-xxhdpi/page_hover_left.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_left_active.9.png b/res/drawable-xxhdpi/page_hover_left_active.9.png
deleted file mode 100644
index 858a3b2..0000000
--- a/res/drawable-xxhdpi/page_hover_left_active.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_right.9.png b/res/drawable-xxhdpi/page_hover_right.9.png
deleted file mode 100644
index c529770..0000000
--- a/res/drawable-xxhdpi/page_hover_right.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_right_active.9.png b/res/drawable-xxhdpi/page_hover_right_active.9.png
deleted file mode 100644
index 9900553..0000000
--- a/res/drawable-xxhdpi/page_hover_right_active.9.png
+++ /dev/null
Binary files differ
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index f431fb1..951a30e 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -50,6 +50,10 @@
android:layout_gravity="right" />
<include
+ android:id="@+id/app_info_drop_target_bar"
+ layout="@layout/app_info_drop_target_bar" />
+
+ <include
android:id="@+id/search_drop_target_bar"
layout="@layout/search_drop_target_bar" />
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index a7f851e..4cb34e9 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -64,6 +64,10 @@
android:layout_gravity="center_horizontal" />
<include
+ android:id="@+id/app_info_drop_target_bar"
+ layout="@layout/app_info_drop_target_bar" />
+
+ <include
android:id="@+id/search_drop_target_bar"
layout="@layout/search_drop_target_bar" />
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 319a493..3228999 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -50,6 +50,10 @@
android:layout_height="match_parent" />
<include
+ android:id="@+id/app_info_drop_target_bar"
+ layout="@layout/app_info_drop_target_bar" />
+
+ <include
android:id="@+id/search_drop_target_bar"
layout="@layout/search_drop_target_bar" />
diff --git a/res/layout/app_info_drop_target_bar.xml b/res/layout/app_info_drop_target_bar.xml
new file mode 100644
index 0000000..b8f30d0
--- /dev/null
+++ b/res/layout/app_info_drop_target_bar.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2011 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.
+-->
+<com.android.launcher3.AppInfoDropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="false" >
+
+ <!-- Drag specific targets container -->
+ <LinearLayout
+ android:id="@+id/drag_target_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center|bottom" >
+
+ <FrameLayout
+ style="@style/DropTargetButtonContainer"
+ android:layout_weight="1" >
+
+ <!-- Info target -->
+
+ <com.android.launcher3.InfoDropTarget
+ android:id="@+id/info_target_text"
+ style="@style/DropTargetButton"
+ android:text="@string/info_target_label" />
+ </FrameLayout>
+ </LinearLayout>
+
+</com.android.launcher3.AppInfoDropTargetBar>
\ No newline at end of file
diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml
index 4737ee1..724eb94 100644
--- a/res/layout/search_drop_target_bar.xml
+++ b/res/layout/search_drop_target_bar.xml
@@ -43,18 +43,6 @@
style="@style/DropTargetButtonContainer"
android:layout_weight="1" >
- <!-- Info target -->
-
- <com.android.launcher3.InfoDropTarget
- android:id="@+id/info_target_text"
- style="@style/DropTargetButton"
- android:text="@string/info_target_label" />
- </FrameLayout>
-
- <FrameLayout
- style="@style/DropTargetButtonContainer"
- android:layout_weight="1" >
-
<!-- Uninstall target -->
<com.android.launcher3.UninstallDropTarget
diff --git a/src/com/android/launcher3/AppInfoDropTargetBar.java b/src/com/android/launcher3/AppInfoDropTargetBar.java
new file mode 100644
index 0000000..31ff42a
--- /dev/null
+++ b/src/com/android/launcher3/AppInfoDropTargetBar.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 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;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.launcher3.dragndrop.DragController;
+
+public class AppInfoDropTargetBar extends BaseDropTargetBar {
+ private ButtonDropTarget mAppInfoDropTarget;
+
+ public AppInfoDropTargetBar(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AppInfoDropTargetBar(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ // Get the individual components
+ mAppInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text);
+
+ mAppInfoDropTarget.setDropTargetBar(this);
+ }
+
+ @Override
+ public void setup(Launcher launcher, DragController dragController) {
+ dragController.addDragListener(this);
+
+ dragController.addDragListener(mAppInfoDropTarget);
+
+ dragController.addDropTarget(mAppInfoDropTarget);
+
+ mAppInfoDropTarget.setLauncher(launcher);
+ }
+
+ @Override
+ public void showDropTarget() {
+ animateDropTargetBarToAlpha(1f, DEFAULT_DRAG_FADE_DURATION);
+ }
+
+ @Override
+ public void hideDropTarget() {
+ animateDropTargetBarToAlpha(0f, DEFAULT_DRAG_FADE_DURATION);
+ }
+
+ private void animateDropTargetBarToAlpha(float alpha, int duration) {
+ animateViewAlpha(mDropTargetBarAnimator, mDropTargetBar, alpha,duration);
+ }
+
+ @Override
+ public void enableAccessibleDrag(boolean enable) {
+ mAppInfoDropTarget.enableAccessibleDrag(enable);
+ }
+}
diff --git a/src/com/android/launcher3/BaseDropTargetBar.java b/src/com/android/launcher3/BaseDropTargetBar.java
new file mode 100644
index 0000000..f478a35
--- /dev/null
+++ b/src/com/android/launcher3/BaseDropTargetBar.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 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;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.dragndrop.DragController;
+
+/**
+ * Base class for drop target bars (where you can drop apps to do actions such as uninstall).
+ */
+public abstract class BaseDropTargetBar extends FrameLayout implements DragController.DragListener {
+ protected static final int DEFAULT_DRAG_FADE_DURATION = 175;
+
+ protected View mDropTargetBar;
+
+ protected LauncherViewPropertyAnimator mDropTargetBarAnimator;
+ protected static final AccelerateInterpolator sAccelerateInterpolator =
+ new AccelerateInterpolator();
+ protected boolean mAccessibilityEnabled = false;
+
+ protected boolean mDeferOnDragEnd;
+
+ public BaseDropTargetBar(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BaseDropTargetBar(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mDropTargetBar = findViewById(R.id.drag_target_bar);
+
+ // Create the various fade animations
+ mDropTargetBar.setAlpha(0f);
+ mDropTargetBarAnimator = new LauncherViewPropertyAnimator(mDropTargetBar);
+ mDropTargetBarAnimator.setInterpolator(sAccelerateInterpolator);
+ mDropTargetBarAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Ensure that the view is visible for the animation
+ mDropTargetBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mDropTargetBar != null) {
+ AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
+ }
+ }
+ });
+ }
+
+
+ /**
+ * Convenience method to animate the alpha of a view using hardware layers.
+ */
+ protected void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha,
+ int duration) {
+ if (v == null) {
+ return;
+ }
+
+ animator.cancel();
+ if (Float.compare(v.getAlpha(), alpha) != 0) {
+ if (duration > 0) {
+ animator.alpha(alpha).withLayer().setDuration(duration).start();
+ } else {
+ v.setAlpha(alpha);
+ AlphaUpdateListener.updateVisibility(v, mAccessibilityEnabled);
+ }
+ }
+ }
+
+ /*
+ * DragController.DragListener implementation
+ */
+ @Override
+ public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+ showDropTarget();
+ }
+
+ /**
+ * This is called to defer hiding the delete drop target until the drop animation has completed,
+ * instead of hiding immediately when the drag has ended.
+ */
+ protected void deferOnDragEnd() {
+ mDeferOnDragEnd = true;
+ }
+
+ @Override
+ public void onDragEnd() {
+ if (!mDeferOnDragEnd) {
+ hideDropTarget();
+ } else {
+ mDeferOnDragEnd = false;
+ }
+ }
+
+ public abstract void showDropTarget();
+
+ public abstract void hideDropTarget();
+
+ public abstract void enableAccessibleDrag(boolean enable);
+
+ public abstract void setup(Launcher launcher, DragController dragController);
+}
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index dc29f7d..703de53 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -49,11 +49,11 @@
public abstract class ButtonDropTarget extends TextView
implements DropTarget, DragController.DragListener, OnClickListener {
- private static int DRAG_VIEW_DROP_DURATION = 285;
+ private static final int DRAG_VIEW_DROP_DURATION = 285;
protected Launcher mLauncher;
private int mBottomDragPadding;
- protected SearchDropTargetBar mSearchDropTargetBar;
+ protected BaseDropTargetBar mDropTargetBar;
/** Whether this drop target is active for the current drag */
protected boolean mActive;
@@ -106,8 +106,8 @@
mLauncher = launcher;
}
- public void setSearchDropTargetBar(SearchDropTargetBar searchDropTargetBar) {
- mSearchDropTargetBar = searchDropTargetBar;
+ public void setDropTargetBar(BaseDropTargetBar dropTargetBar) {
+ mDropTargetBar = dropTargetBar;
}
@Override
@@ -230,13 +230,13 @@
final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
width, height);
final float scale = (float) to.width() / from.width();
- mSearchDropTargetBar.deferOnDragEnd();
+ mDropTargetBar.deferOnDragEnd();
Runnable onAnimationEndRunnable = new Runnable() {
@Override
public void run() {
completeDrop(d);
- mSearchDropTargetBar.onDragEnd();
+ mDropTargetBar.onDragEnd();
mLauncher.exitSpringLoadedDragModeDelayed(true, 0, null);
}
};
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 700bf9e..b8b4144 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -2685,6 +2685,7 @@
LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.dropped = true;
child.requestLayout();
+ markCellsAsOccupiedForView(child);
}
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 9a9b57a..6d8fa6b 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -19,7 +19,6 @@
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.PointF;
-import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AnimationUtils;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 6364d90..69ef826 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -372,7 +372,7 @@
* When {@code true}, hotseat is on the bottom row when in landscape mode.
* If {@code false}, hotseat is on the right column when in landscape mode.
*/
- boolean isVerticalBarLayout() {
+ public boolean isVerticalBarLayout() {
return isLandscape && transposeLayoutWithOrientation;
}
@@ -397,29 +397,15 @@
// Layout the search bar space
View searchBar = launcher.getSearchDropTargetBar();
- lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
- if (hasVerticalBarLayout) {
- // Vertical search bar space -- The search bar is fixed in the layout to be on the left
- // of the screen regardless of RTL
- lp.gravity = Gravity.LEFT;
- lp.width = searchBarSpaceHeightPx;
-
- LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
- targets.setOrientation(LinearLayout.VERTICAL);
- FrameLayout.LayoutParams targetsLp = (FrameLayout.LayoutParams) targets.getLayoutParams();
- targetsLp.gravity = Gravity.TOP;
- targetsLp.height = LayoutParams.WRAP_CONTENT;
-
- } else {
- // Horizontal search bar space
- lp.gravity = Gravity.TOP;
- lp.height = searchBarSpaceHeightPx;
-
- LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
- targets.getLayoutParams().width = searchBarSpaceWidthPx;
- }
+ lp = getDropTargetBarLayoutParams(hasVerticalBarLayout, searchBar, Gravity.TOP);
searchBar.setLayoutParams(lp);
+ // Layout the app info bar space
+ View appInfoBar = launcher.getAppInfoDropTargetBar();
+ lp = getDropTargetBarLayoutParams(hasVerticalBarLayout, appInfoBar, Gravity.BOTTOM);
+ lp.bottomMargin = hotseatBarHeightPx;
+ appInfoBar.setLayoutParams(lp);
+
// Layout the workspace
PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
lp = (FrameLayout.LayoutParams) workspace.getLayoutParams();
@@ -478,7 +464,6 @@
// Layout the Overview Mode
ViewGroup overviewMode = launcher.getOverviewPanel();
if (overviewMode != null) {
- int overviewButtonBarHeight = getOverviewModeButtonBarHeight();
lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
@@ -487,7 +472,7 @@
int maxWidth = totalItemWidth + (visibleChildCount-1) * overviewModeBarSpacerWidthPx;
lp.width = Math.min(availableWidthPx, maxWidth);
- lp.height = overviewButtonBarHeight;
+ lp.height = getOverviewModeButtonBarHeight();
overviewMode.setLayoutParams(lp);
if (lp.width > totalItemWidth && visibleChildCount > 1) {
@@ -516,6 +501,31 @@
}
}
+ private FrameLayout.LayoutParams getDropTargetBarLayoutParams(boolean hasVerticalBarLayout,
+ View dropTargetBar, int verticalGravity) {
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) dropTargetBar.getLayoutParams();
+ if (hasVerticalBarLayout) {
+ // Vertical drop target bar space -- The drop target bar is fixed in the layout to be on
+ // the left of the screen regardless of RTL
+ lp.gravity = Gravity.LEFT;
+ lp.width = searchBarSpaceHeightPx;
+
+ LinearLayout targets = (LinearLayout) dropTargetBar.findViewById(R.id.drag_target_bar);
+ targets.setOrientation(LinearLayout.VERTICAL);
+ FrameLayout.LayoutParams targetsLp = (FrameLayout.LayoutParams) targets.getLayoutParams();
+ targetsLp.gravity = verticalGravity;
+ targetsLp.height = LayoutParams.WRAP_CONTENT;
+ } else {
+ // Horizontal drop target bar space
+ lp.gravity = verticalGravity;
+ lp.height = searchBarSpaceHeightPx;
+
+ LinearLayout targets = (LinearLayout) dropTargetBar.findViewById(R.id.drag_target_bar);
+ targets.getLayoutParams().width = searchBarSpaceWidthPx;
+ }
+ return lp;
+ }
+
private int getCurrentWidth() {
return isLandscape
? Math.max(widthPx, heightPx)
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index e85fce6..ff21be2 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -906,7 +906,7 @@
@Override
public boolean supportsAppInfoDropTarget() {
- return false;
+ return true;
}
@Override
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index b4a1445..006ce5d 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -20,7 +20,7 @@
import android.content.Context;
import android.util.AttributeSet;
-public class InfoDropTarget extends ButtonDropTarget {
+public class InfoDropTarget extends UninstallDropTarget {
public InfoDropTarget(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -39,7 +39,10 @@
setDrawable(R.drawable.ic_info_launcher);
}
- public static void startDetailsActivityForInfo(ItemInfo info, Launcher launcher) {
+ /**
+ * @return Whether the activity was started.
+ */
+ public static boolean startDetailsActivityForInfo(ItemInfo info, Launcher launcher) {
ComponentName componentName = null;
if (info instanceof AppInfo) {
componentName = ((AppInfo) info).componentName;
@@ -50,7 +53,14 @@
}
if (componentName != null) {
launcher.startApplicationDetailsActivity(componentName, info.user);
+ return true;
}
+ return false;
+ }
+
+ @Override
+ protected boolean startActivityWithUninstallAffordance(DragObject d) {
+ return startDetailsActivityForInfo(d.dragInfo, mLauncher);
}
@Override
@@ -59,11 +69,7 @@
}
public static boolean supportsDrop(Context context, ItemInfo info) {
- return info instanceof AppInfo || info instanceof PendingAddItemInfo;
- }
-
- @Override
- void completeDrop(DragObject d) {
- startDetailsActivityForInfo(d.dragInfo, mLauncher);
+ return info instanceof AppInfo || info instanceof ShortcutInfo
+ || info instanceof PendingAddItemInfo;
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 17b72b7..11869d9 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -200,7 +200,8 @@
public static final String USER_HAS_MIGRATED = "launcher.user_migrated_from_old_data";
/** The different states that Launcher can be in. */
- enum State { NONE, WORKSPACE, APPS, APPS_SPRING_LOADED, WIDGETS, WIDGETS_SPRING_LOADED }
+ enum State { NONE, WORKSPACE, WORKSPACE_SPRING_LOADED, APPS, APPS_SPRING_LOADED,
+ WIDGETS, WIDGETS_SPRING_LOADED }
@Thunk State mState = State.WORKSPACE;
@Thunk LauncherStateTransitionAnimation mStateTransitionAnimation;
@@ -247,6 +248,7 @@
private View mWidgetsButton;
private SearchDropTargetBar mSearchDropTargetBar;
+ private AppInfoDropTargetBar mAppInfoDropTargetBar;
// Main container view for the all apps screen.
@Thunk AllAppsContainerView mAppsView;
@@ -1361,9 +1363,12 @@
mWorkspace.setup(dragController);
dragController.addDragListener(mWorkspace);
- // Get the search/delete bar
+ // Get the search/delete/uninstall bar
mSearchDropTargetBar = (SearchDropTargetBar)
mDragLayer.findViewById(R.id.search_drop_target_bar);
+ // Get the app info bar
+ mAppInfoDropTargetBar = (AppInfoDropTargetBar)
+ mDragLayer.findViewById(R.id.app_info_drop_target_bar);
// Setup Apps and Widgets
mAppsView = (AllAppsContainerView) findViewById(R.id.apps_view);
@@ -1376,13 +1381,15 @@
// Setup the drag controller (drop targets have to be added in reverse order in priority)
dragController.setDragScoller(mWorkspace);
- dragController.setScrollView(mDragLayer);
dragController.setMoveTarget(mWorkspace);
dragController.addDropTarget(mWorkspace);
if (mSearchDropTargetBar != null) {
mSearchDropTargetBar.setup(this, dragController);
mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
}
+ if (mAppInfoDropTargetBar != null) {
+ mAppInfoDropTargetBar.setup(this, dragController);
+ }
if (getResources().getBoolean(R.bool.debug_memory_enabled)) {
Log.v(TAG, "adding WeightWatcher");
@@ -1769,6 +1776,10 @@
return mSearchDropTargetBar;
}
+ public AppInfoDropTargetBar getAppInfoDropTargetBar() {
+ return mAppInfoDropTargetBar;
+ }
+
public LauncherAppWidgetHost getAppWidgetHost() {
return mAppWidgetHost;
}
@@ -3376,20 +3387,26 @@
public void enterSpringLoadedDragMode() {
if (LOGD) Log.d(TAG, String.format("enterSpringLoadedDragMode [mState=%s", mState.name()));
- if (mState == State.WORKSPACE || mState == State.APPS_SPRING_LOADED ||
- mState == State.WIDGETS_SPRING_LOADED) {
+ if (isStateSpringLoaded()) {
return;
}
mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(),
Workspace.State.SPRING_LOADED, true /* animated */,
null /* onCompleteRunnable */);
- mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED;
+
+ if (isAppsViewVisible()) {
+ mState = State.APPS_SPRING_LOADED;
+ } else if (isWidgetsViewVisible()) {
+ mState = State.WIDGETS_SPRING_LOADED;
+ } else {
+ mState = State.WORKSPACE_SPRING_LOADED;
+ }
}
public void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay,
final Runnable onCompleteRunnable) {
- if (mState != State.APPS_SPRING_LOADED && mState != State.WIDGETS_SPRING_LOADED) return;
+ if (!isStateSpringLoaded()) return;
mHandler.postDelayed(new Runnable() {
@Override
@@ -3409,12 +3426,19 @@
}, delay);
}
+ private boolean isStateSpringLoaded() {
+ return mState == State.WORKSPACE_SPRING_LOADED || mState == State.APPS_SPRING_LOADED
+ || mState == State.WIDGETS_SPRING_LOADED;
+ }
+
void exitSpringLoadedDragMode() {
if (mState == State.APPS_SPRING_LOADED) {
showAppsView(true /* animated */, false /* resetListToTop */,
false /* updatePredictedApps */, false /* focusSearchBar */);
} else if (mState == State.WIDGETS_SPRING_LOADED) {
showWidgetsView(true, false);
+ } else if (mState == State.WORKSPACE_SPRING_LOADED) {
+ showWorkspace(true);
}
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 3007269..b4095a6 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -34,6 +34,7 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.os.DeadObjectException;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -166,6 +167,9 @@
// sBgWidgetProviders is the set of widget providers including custom internal widgets
public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;
+ // sBgShortcutProviders is the set of custom shortcut providers
+ public static List<ResolveInfo> sBgShortcutProviders;
+
// sPendingPackages is a set of packages which could be on sdcard and are not available yet
static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =
new HashMap<UserHandleCompat, HashSet<String>>();
@@ -3280,9 +3284,18 @@
// Refresh widget list, if there is any newly added widget
PackageManager pm = context.getPackageManager();
for (String pkg : mPackages) {
- needToRefresh |= !pm.queryBroadcastReceivers(
- new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
- .setPackage(pkg), 0).isEmpty();
+ try {
+ List<ResolveInfo> widgets = pm.queryBroadcastReceivers(
+ new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
+ .setPackage(pkg), 0);
+ needToRefresh |= widgets != null && !widgets.isEmpty();
+ } catch (RuntimeException e) {
+ if (ProviderConfig.IS_DOGFOOD_BUILD) {
+ throw e;
+ }
+ // Ignore the crash. We can live with a state widget list.
+ Log.e(TAG, "PM call failed for " + pkg, e);
+ }
}
}
@@ -3334,7 +3347,9 @@
return results;
}
} catch (Exception e) {
- if (e.getCause() instanceof TransactionTooLargeException) {
+ if (!ProviderConfig.IS_DOGFOOD_BUILD &&
+ (e.getCause() instanceof TransactionTooLargeException ||
+ e.getCause() instanceof DeadObjectException)) {
// 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
@@ -3394,8 +3409,29 @@
PackageManager packageManager = mApp.getContext().getPackageManager();
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
widgetsAndShortcuts.addAll(getWidgetProviders(mApp.getContext(), refresh));
- Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
- widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));
+
+ // Update shortcut providers
+ synchronized (sBgLock) {
+ try {
+ Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+ List<ResolveInfo> providers = packageManager.queryIntentActivities(shortcutsIntent, 0);
+ sBgShortcutProviders = providers;
+ } catch (RuntimeException e) {
+ if (!LauncherAppState.isDogfoodBuild() &&
+ (e.getCause() instanceof TransactionTooLargeException ||
+ e.getCause() instanceof DeadObjectException)) {
+ /**
+ * Ignore exception and use the cached list if available.
+ * Refer to {@link #getWidgetProviders(Context, boolean}} for more info.
+ */
+ } else {
+ throw e;
+ }
+ }
+ if (sBgShortcutProviders != null) {
+ widgetsAndShortcuts.addAll(sBgShortcutProviders);
+ }
+ }
mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);
}
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 0e20fab..d3af19a 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -176,7 +176,7 @@
}
/**
- * Starts and animation to the workspace from the current overlay view.
+ * Starts an animation to the workspace from the current overlay view.
*/
public void startAnimationToWorkspace(final Launcher.State fromState,
final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState,
@@ -190,9 +190,13 @@
if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) {
startAnimationToWorkspaceFromAllApps(fromWorkspaceState, toWorkspaceState,
animated, onCompleteRunnable);
- } else {
+ } else if (fromState == Launcher.State.WIDGETS ||
+ fromState == Launcher.State.WIDGETS_SPRING_LOADED) {
startAnimationToWorkspaceFromWidgets(fromWorkspaceState, toWorkspaceState,
animated, onCompleteRunnable);
+ } else {
+ startAnimationToNewWorkspaceState(fromWorkspaceState, toWorkspaceState,
+ animated, onCompleteRunnable);
}
}
@@ -403,7 +407,7 @@
}
/**
- * Starts and animation to the workspace from the apps view.
+ * Starts an animation to the workspace from the apps view.
*/
private void startAnimationToWorkspaceFromAllApps(final Workspace.State fromWorkspaceState,
final Workspace.State toWorkspaceState, final boolean animated,
@@ -448,10 +452,10 @@
}
/**
- * Starts and animation to the workspace from the widgets view.
+ * Starts an animation to the workspace from the widgets view.
*/
private void startAnimationToWorkspaceFromWidgets(final Workspace.State fromWorkspaceState,
- final Workspace.State toWorkspaceState, final boolean animated,
+ final Workspace.State toWorkspaceState, final boolean animated,
final Runnable onCompleteRunnable) {
final WidgetsContainerView widgetsView = mLauncher.getWidgetsView();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
@@ -477,6 +481,95 @@
}
/**
+ * Starts an animation to the workspace from another workspace state, e.g. normal to overview.
+ */
+ private void startAnimationToNewWorkspaceState(final Workspace.State fromWorkspaceState,
+ final Workspace.State toWorkspaceState, final boolean animated,
+ final Runnable onCompleteRunnable) {
+ final View fromWorkspace = mLauncher.getWorkspace();
+ final HashMap<View, Integer> layerViews = new HashMap<>();
+ final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
+ final int revealDuration = mLauncher.getResources()
+ .getInteger(R.integer.config_overlayRevealTime);
+
+ // Cancel the current animation
+ cancelAnimation();
+
+ // Create the workspace animation.
+ // NOTE: this call apparently also sets the state for the workspace if !animated
+ Animator workspaceAnim = mLauncher.startWorkspaceStateChangeAnimation(toWorkspaceState,
+ animated, layerViews);
+
+ startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState,
+ animated ? revealDuration : 0, null);
+
+ if (animated) {
+ if (workspaceAnim != null) {
+ animation.play(workspaceAnim);
+ }
+ dispatchOnLauncherTransitionPrepare(fromWorkspace, animated, true);
+
+ final AnimatorSet stateAnimation = animation;
+ final Runnable startAnimRunnable = new Runnable() {
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public void run() {
+ // Check that mCurrentAnimation hasn't changed while
+ // we waited for a layout/draw pass
+ if (mCurrentAnimation != stateAnimation)
+ return;
+
+ dispatchOnLauncherTransitionStart(fromWorkspace, animated, true);
+
+ // Enable all necessary layers
+ for (View v : layerViews.keySet()) {
+ if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+ v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+ if (Utilities.ATLEAST_LOLLIPOP && v.isAttachedToWindow()) {
+ v.buildLayer();
+ }
+ }
+ stateAnimation.start();
+ }
+ };
+ animation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ dispatchOnLauncherTransitionEnd(fromWorkspace, animated, true);
+
+ // Run any queued runnables
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
+
+ // Disable all necessary layers
+ for (View v : layerViews.keySet()) {
+ if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+ v.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ }
+
+ // This can hold unnecessary references to views.
+ cleanupAnimation();
+ }
+ });
+ fromWorkspace.post(startAnimRunnable);
+ mCurrentAnimation = animation;
+ } else /* if (!animated) */ {
+ dispatchOnLauncherTransitionPrepare(fromWorkspace, animated, true);
+ dispatchOnLauncherTransitionStart(fromWorkspace, animated, true);
+ dispatchOnLauncherTransitionEnd(fromWorkspace, animated, true);
+
+ // Run any queued runnables
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
+
+ mCurrentAnimation = null;
+ }
+ }
+
+ /**
* Creates and starts a new animation to the workspace.
*/
private AnimatorSet startAnimationToWorkspaceFromOverlay(final Workspace.State fromWorkspaceState,
@@ -683,7 +776,7 @@
fromView.post(startAnimRunnable);
return animation;
- } else {
+ } else /* if (!(animated && initialized)) */ {
fromView.setVisibility(View.GONE);
dispatchOnLauncherTransitionPrepare(fromView, animated, true);
dispatchOnLauncherTransitionStart(fromView, animated, true);
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
index fdcad82..878a474 100644
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ b/src/com/android/launcher3/SearchDropTargetBar.java
@@ -23,17 +23,15 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.FrameLayout;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.util.Thunk;
/*
- * Ths bar will manage the transition between the QSB search bar and the delete drop
- * targets so that each of the individual IconDropTargets don't have to.
+ * This bar will manage the transition between the QSB search bar and the delete/uninstall drop
+ * targets so that each of the individual ButtonDropTargets don't have to.
*/
-public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
+public class SearchDropTargetBar extends BaseDropTargetBar {
/** The different states that the search bar space can be in. */
public enum State {
@@ -58,21 +56,13 @@
}
}
- private static int DEFAULT_DRAG_FADE_DURATION = 175;
- private LauncherViewPropertyAnimator mDropTargetBarAnimator;
private LauncherViewPropertyAnimator mQSBSearchBarAnimator;
- private static final AccelerateInterpolator sAccelerateInterpolator =
- new AccelerateInterpolator();
private State mState = State.SEARCH_BAR;
@Thunk View mQSB;
- @Thunk View mDropTargetBar;
- private boolean mDeferOnDragEnd = false;
- @Thunk boolean mAccessibilityEnabled = false;
// Drop targets
- private ButtonDropTarget mInfoDropTarget;
private ButtonDropTarget mDeleteDropTarget;
private ButtonDropTarget mUninstallDropTarget;
@@ -84,61 +74,48 @@
super(context, attrs, defStyle);
}
- public void setup(Launcher launcher, DragController dragController) {
- dragController.addDragListener(this);
- dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
-
- dragController.addDragListener(mInfoDropTarget);
- dragController.addDragListener(mDeleteDropTarget);
- dragController.addDragListener(mUninstallDropTarget);
-
- dragController.addDropTarget(mInfoDropTarget);
- dragController.addDropTarget(mDeleteDropTarget);
- dragController.addDropTarget(mUninstallDropTarget);
-
- mInfoDropTarget.setLauncher(launcher);
- mDeleteDropTarget.setLauncher(launcher);
- mUninstallDropTarget.setLauncher(launcher);
- }
-
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// Get the individual components
- mDropTargetBar = findViewById(R.id.drag_target_bar);
- mInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text);
mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text);
- mUninstallDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.uninstall_target_text);
+ mUninstallDropTarget = (ButtonDropTarget) mDropTargetBar
+ .findViewById(R.id.uninstall_target_text);
- mInfoDropTarget.setSearchDropTargetBar(this);
- mDeleteDropTarget.setSearchDropTargetBar(this);
- mUninstallDropTarget.setSearchDropTargetBar(this);
+ mDeleteDropTarget.setDropTargetBar(this);
+ mUninstallDropTarget.setDropTargetBar(this);
+ }
- // Create the various fade animations
- mDropTargetBar.setAlpha(0f);
- mDropTargetBarAnimator = new LauncherViewPropertyAnimator(mDropTargetBar);
- mDropTargetBarAnimator.setInterpolator(sAccelerateInterpolator);
- mDropTargetBarAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- // Ensure that the view is visible for the animation
- mDropTargetBar.setVisibility(View.VISIBLE);
- }
+ @Override
+ public void setup(Launcher launcher, DragController dragController) {
+ dragController.addDragListener(this);
+ dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mDropTargetBar != null) {
- AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
- }
- }
- });
+ dragController.addDragListener(mDeleteDropTarget);
+ dragController.addDragListener(mUninstallDropTarget);
+
+ dragController.addDropTarget(mDeleteDropTarget);
+ dragController.addDropTarget(mUninstallDropTarget);
+
+ mDeleteDropTarget.setLauncher(launcher);
+ mUninstallDropTarget.setLauncher(launcher);
+ }
+
+ @Override
+ public void showDropTarget() {
+ animateToState(State.DROP_TARGET, DEFAULT_DRAG_FADE_DURATION);
+ }
+
+ @Override
+ public void hideDropTarget() {
+ animateToState(State.SEARCH_BAR, DEFAULT_DRAG_FADE_DURATION);
}
public void setQsbSearchBar(View qsb) {
mQSB = qsb;
if (mQSB != null) {
- // Update the search ber animation
+ // Update the search bar animation
mQSBSearchBarAnimator = new LauncherViewPropertyAnimator(mQSB);
mQSBSearchBarAnimator.setInterpolator(sAccelerateInterpolator);
mQSBSearchBarAnimator.addListener(new AnimatorListenerAdapter() {
@@ -183,51 +160,6 @@
}
/**
- * Convenience method to animate the alpha of a view using hardware layers.
- */
- private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha,
- int duration) {
- if (v == null) {
- return;
- }
-
- animator.cancel();
- if (Float.compare(v.getAlpha(), alpha) != 0) {
- if (duration > 0) {
- animator.alpha(alpha).withLayer().setDuration(duration).start();
- } else {
- v.setAlpha(alpha);
- AlphaUpdateListener.updateVisibility(v, mAccessibilityEnabled);
- }
- }
- }
-
- /*
- * DragController.DragListener implementation
- */
- @Override
- public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
- animateToState(State.DROP_TARGET, DEFAULT_DRAG_FADE_DURATION);
- }
-
- /**
- * This is called to defer hiding the delete drop target until the drop animation has completed,
- * instead of hiding immediately when the drag has ended.
- */
- public void deferOnDragEnd() {
- mDeferOnDragEnd = true;
- }
-
- @Override
- public void onDragEnd() {
- if (!mDeferOnDragEnd) {
- animateToState(State.SEARCH_BAR, DEFAULT_DRAG_FADE_DURATION);
- } else {
- mDeferOnDragEnd = false;
- }
- }
-
- /**
* @return the bounds of the QSB search bar.
*/
public Rect getSearchBarBounds() {
@@ -246,11 +178,11 @@
}
}
+ @Override
public void enableAccessibleDrag(boolean enable) {
if (mQSB != null) {
mQSB.setVisibility(enable ? View.GONE : View.VISIBLE);
}
- mInfoDropTarget.enableAccessibleDrag(enable);
mDeleteDropTarget.enableAccessibleDrag(enable);
mUninstallDropTarget.enableAccessibleDrag(enable);
}
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 9ed4fb6..b69c79d 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -82,7 +82,7 @@
void completeDrop(final DragObject d) {
final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(d.dragInfo);
final UserHandleCompat user = d.dragInfo.user;
- if (startUninstallActivity(mLauncher, d.dragInfo)) {
+ if (startActivityWithUninstallAffordance(d)) {
final Runnable checkIfUninstallWasSuccess = new Runnable() {
@Override
@@ -99,6 +99,10 @@
}
}
+ protected boolean startActivityWithUninstallAffordance(DragObject d) {
+ return startUninstallActivity(mLauncher, d.dragInfo);
+ }
+
public static boolean startUninstallActivity(Launcher launcher, ItemInfo info) {
final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
final UserHandleCompat user = info.user;
@@ -115,7 +119,7 @@
/**
* Interface defining an object that can provide uninstallable drag objects.
*/
- public static interface UninstallSource {
+ public interface UninstallSource {
/**
* A pending uninstall operation was complete.
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 1539658..b59d85d 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1582,6 +1582,7 @@
setOnClickListener(mLauncher);
}
mLauncher.getSearchDropTargetBar().enableAccessibleDrag(enable);
+ mLauncher.getAppInfoDropTargetBar().enableAccessibleDrag(enable);
mLauncher.getHotseat().getLayout()
.enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
}
@@ -1998,6 +1999,10 @@
return -workspaceOffsetTopEdge + overviewOffsetTopEdge;
}
+ int getSpringLoadedTranslationY() {
+ return getOverviewModeTranslationY();
+ }
+
/**
* Sets the current workspace {@link State}, returning an animation transitioning the workspace
* to that new state.
@@ -2341,6 +2346,8 @@
dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
b.recycle();
+
+ mLauncher.enterSpringLoadedDragMode();
}
public void beginExternalDragShared(View child, DragSource source) {
@@ -2389,6 +2396,8 @@
// Recycle temporary bitmaps
tmpB.recycle();
+
+ mLauncher.enterSpringLoadedDragMode();
}
public boolean transitionStateShouldAllowDrop() {
@@ -2846,10 +2855,6 @@
CellLayout layout = getCurrentDropLayout();
setCurrentDropLayout(layout);
setCurrentDragOverlappingLayout(layout);
-
- if (!workspaceInModalState()) {
- mLauncher.getDragLayer().showPageHints();
- }
}
@Override
@@ -2884,8 +2889,6 @@
setCurrentDragOverlappingLayout(null);
mSpringLoadedDragController.cancel();
-
- mLauncher.getDragLayer().hidePageHints();
}
private void enfoceDragParity(String event, int update, int expectedValue) {
@@ -3720,6 +3723,9 @@
}
mDragOutline = null;
mDragInfo = null;
+
+ mLauncher.exitSpringLoadedDragModeDelayed(success,
+ Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
}
/**
@@ -3809,7 +3815,7 @@
@Override
public boolean supportsAppInfoDropTarget() {
- return false;
+ return true;
}
@Override
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 011f4a2..d32ce73 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -285,8 +285,13 @@
float finalHotseatAndPageIndicatorAlpha = (states.stateIsNormal || states.stateIsSpringLoaded) ?
1f : 0f;
float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f;
- float finalWorkspaceTranslationY = states.stateIsOverview || states.stateIsOverviewHidden ?
- mWorkspace.getOverviewModeTranslationY() : 0;
+
+ float finalWorkspaceTranslationY = 0;
+ if (states.stateIsOverview || states.stateIsOverviewHidden) {
+ finalWorkspaceTranslationY = mWorkspace.getOverviewModeTranslationY();
+ } else if (states.stateIsSpringLoaded) {
+ finalWorkspaceTranslationY = mWorkspace.getSpringLoadedTranslationY();
+ }
final int childCount = mWorkspace.getChildCount();
final int customPageCount = mWorkspace.numCustomPages();
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 41b4e04..979a733 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -477,8 +477,6 @@
// Start the drag
mLauncher.getWorkspace().beginDragShared(v, mIconLastTouchPos, this, false);
- // Enter spring loaded mode
- mLauncher.enterSpringLoadedDragMode();
return false;
}
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 8777dc6..4a39e6b 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -42,7 +42,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.PagedView;
import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.R;
@@ -82,7 +81,6 @@
// temporaries to avoid gc thrash
private Rect mRectTemp = new Rect();
private final int[] mCoordinatesTemp = new int[2];
- private final boolean mIsRtl;
/**
* Drag driver for the current drag/drop operation, or null if there is no active DND operation.
@@ -99,11 +97,6 @@
/** Y coordinate of the down event. */
private int mMotionDownY;
- /** the area at the edge of the screen that makes the workspace go left
- * or right while you're dragging.
- */
- private final int mScrollZone;
-
private DropTarget.DragObject mDragObject;
/** Who can receive drop events */
@@ -114,9 +107,6 @@
/** The window token used as the parent for the DragView. */
private IBinder mWindowToken;
- /** The view that will be scrolled when dragging to the left and right edges of the screen. */
- private View mScrollView;
-
private View mMoveTarget;
@Thunk DragScroller mDragScroller;
@@ -129,7 +119,6 @@
@Thunk int mLastTouch[] = new int[2];
@Thunk long mLastTouchUpTime = -1;
- @Thunk int mDistanceSinceScroll = 0;
private int mTmpPoint[] = new int[2];
private Rect mDragLayerRect = new Rect();
@@ -159,19 +148,15 @@
/**
* Used to create a new DragLayer from XML.
- *
- * @param context The application's context.
*/
public DragController(Launcher launcher) {
Resources r = launcher.getResources();
mLauncher = launcher;
mHandler = new Handler();
- mScrollZone = r.getDimensionPixelSize(R.dimen.scroll_zone);
mVelocityTracker = VelocityTracker.obtain();
mFlingToDeleteThresholdVelocity =
r.getDimensionPixelSize(R.dimen.drag_flingToDeleteMinVelocity);
- mIsRtl = Utilities.isRtl(r);
}
/**
@@ -559,7 +544,6 @@
mScrollState = SCROLL_OUTSIDE_ZONE;
mScrollRunnable.setDirection(SCROLL_RIGHT);
mDragScroller.onExitScrollArea();
- mLauncher.getDragLayer().onExitScrollArea();
}
}
@@ -573,11 +557,8 @@
mDragObject.y = coordinates[1];
checkTouchMove(dropTarget);
- // Check if we are hovering over the scroll areas
- mDistanceSinceScroll += Math.hypot(mLastTouch[0] - x, mLastTouch[1] - y);
mLastTouch[0] = x;
mLastTouch[1] = y;
- checkScrollState(x, y);
}
public void forceTouchMove() {
@@ -605,36 +586,6 @@
mLastDropTarget = dropTarget;
}
- @Thunk void checkScrollState(int x, int y) {
- final int slop = ViewConfiguration.get(mLauncher).getScaledWindowTouchSlop();
- final int delay = mDistanceSinceScroll < slop ? RESCROLL_DELAY : SCROLL_DELAY;
- final DragLayer dragLayer = mLauncher.getDragLayer();
- final int forwardDirection = mIsRtl ? SCROLL_RIGHT : SCROLL_LEFT;
- final int backwardsDirection = mIsRtl ? SCROLL_LEFT : SCROLL_RIGHT;
-
- if (x < mScrollZone) {
- if (mScrollState == SCROLL_OUTSIDE_ZONE) {
- mScrollState = SCROLL_WAITING_IN_ZONE;
- if (mDragScroller.onEnterScrollArea(x, y, forwardDirection)) {
- dragLayer.onEnterScrollArea(forwardDirection);
- mScrollRunnable.setDirection(forwardDirection);
- mHandler.postDelayed(mScrollRunnable, delay);
- }
- }
- } else if (x > mScrollView.getWidth() - mScrollZone) {
- if (mScrollState == SCROLL_OUTSIDE_ZONE) {
- mScrollState = SCROLL_WAITING_IN_ZONE;
- if (mDragScroller.onEnterScrollArea(x, y, backwardsDirection)) {
- dragLayer.onEnterScrollArea(backwardsDirection);
- mScrollRunnable.setDirection(backwardsDirection);
- mHandler.postDelayed(mScrollRunnable, delay);
- }
- }
- } else {
- clearScrollRunnable();
- }
- }
-
/**
* Call this from a drag source view.
*/
@@ -656,13 +607,6 @@
// Remember where the motion event started
mMotionDownX = dragLayerX;
mMotionDownY = dragLayerY;
-
- if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
- mScrollState = SCROLL_WAITING_IN_ZONE;
- mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
- } else {
- mScrollState = SCROLL_OUTSIDE_ZONE;
- }
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
@@ -712,21 +656,29 @@
ViewConfiguration config = ViewConfiguration.get(mLauncher);
mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
-
+ PointF vel = new PointF(mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
+ float theta = MAX_FLING_DEGREES + 1;
if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
// Do a quick dot product test to ensure that we are flinging upwards
- PointF vel = new PointF(mVelocityTracker.getXVelocity(),
- mVelocityTracker.getYVelocity());
PointF upVec = new PointF(0f, -1f);
- float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
- (vel.length() * upVec.length()));
- if (theta <= Math.toRadians(MAX_FLING_DEGREES)) {
- return vel;
- }
+ theta = getAngleBetweenVectors(vel, upVec);
+ } else if (mLauncher.getDeviceProfile().isVerticalBarLayout() &&
+ mVelocityTracker.getXVelocity() < mFlingToDeleteThresholdVelocity) {
+ // Remove icon is on left side instead of top, so check if we are flinging to the left.
+ PointF leftVec = new PointF(-1f, 0f);
+ theta = getAngleBetweenVectors(vel, leftVec);
+ }
+ if (theta <= Math.toRadians(MAX_FLING_DEGREES)) {
+ return vel;
}
return null;
}
+ private float getAngleBetweenVectors(PointF vec1, PointF vec2) {
+ return (float) Math.acos(((vec1.x * vec2.x) + (vec1.y * vec2.y)) /
+ (vec1.length() * vec2.length()));
+ }
+
void drop(DropTarget dropTarget, float x, float y, PointF flingVel) {
final int[] coordinates = mCoordinatesTemp;
@@ -847,13 +799,6 @@
}
}
- /**
- * Set which view scrolls for touch events near the edge of the screen.
- */
- public void setScrollView(View v) {
- mScrollView = v;
- }
-
private class ScrollRunnable implements Runnable {
private int mDirection;
@@ -868,14 +813,7 @@
mDragScroller.scrollRight();
}
mScrollState = SCROLL_OUTSIDE_ZONE;
- mDistanceSinceScroll = 0;
mDragScroller.onExitScrollArea();
- mLauncher.getDragLayer().onExitScrollArea();
-
- if (isDragging()) {
- // Check the scroll again so that we can requeue the scroller if necessary
- checkScrollState(mLastTouch[0], mLastTouch[1]);
- }
}
}
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 741d5e6..adcc12c 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -102,15 +102,6 @@
// Darkening scrim
private float mBackgroundAlpha = 0;
- // Related to adjacent page hints
- private final Rect mScrollChildPosition = new Rect();
- private boolean mInScrollArea;
- private boolean mShowPageHints;
- private Drawable mLeftHoverDrawable;
- private Drawable mRightHoverDrawable;
- private Drawable mLeftHoverDrawableActive;
- private Drawable mRightHoverDrawableActive;
-
private boolean mBlockTouches = false;
/**
@@ -126,12 +117,7 @@
setMotionEventSplittingEnabled(false);
setChildrenDrawingOrderEnabled(true);
- final Resources res = getResources();
- mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left);
- mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right);
- mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
- mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
- mIsRtl = Utilities.isRtl(res);
+ mIsRtl = Utilities.isRtl(getResources());
}
public void setup(Launcher launcher, DragController controller) {
@@ -179,6 +165,11 @@
if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
return true;
}
+
+ getDescendantRectRelativeToSelf(mLauncher.getAppInfoDropTargetBar(), mHitRect);
+ if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
+ return true;
+ }
return false;
}
@@ -338,6 +329,7 @@
if (isInAccessibleDrag()) {
childrenForAccessibility.add(mLauncher.getSearchDropTargetBar());
+ childrenForAccessibility.add(mLauncher.getAppInfoDropTargetBar());
}
} else {
super.addChildrenForAccessibility(childrenForAccessibility);
@@ -895,29 +887,6 @@
}
}
- void onEnterScrollArea(int direction) {
- mInScrollArea = true;
- invalidate();
- }
-
- void onExitScrollArea() {
- mInScrollArea = false;
- invalidate();
- }
-
- public void showPageHints() {
- mShowPageHints = true;
- Workspace workspace = mLauncher.getWorkspace();
- getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.numCustomPages()),
- mScrollChildPosition);
- invalidate();
- }
-
- public void hidePageHints() {
- mShowPageHints = false;
- invalidate();
- }
-
@Override
protected void dispatchDraw(Canvas canvas) {
// Draw the background below children.
@@ -929,41 +898,6 @@
super.dispatchDraw(canvas);
}
- private void drawPageHints(Canvas canvas) {
- if (mShowPageHints) {
- Workspace workspace = mLauncher.getWorkspace();
- int width = getMeasuredWidth();
- int page = workspace.getNextPage();
- CellLayout leftPage = (CellLayout) workspace.getChildAt(mIsRtl ? page + 1 : page - 1);
- CellLayout rightPage = (CellLayout) workspace.getChildAt(mIsRtl ? page - 1 : page + 1);
-
- if (leftPage != null && leftPage.isDragTarget()) {
- Drawable left = mInScrollArea && leftPage.getIsDragOverlapping() ?
- mLeftHoverDrawableActive : mLeftHoverDrawable;
- left.setBounds(0, mScrollChildPosition.top,
- left.getIntrinsicWidth(), mScrollChildPosition.bottom);
- left.draw(canvas);
- }
- if (rightPage != null && rightPage.isDragTarget()) {
- Drawable right = mInScrollArea && rightPage.getIsDragOverlapping() ?
- mRightHoverDrawableActive : mRightHoverDrawable;
- right.setBounds(width - right.getIntrinsicWidth(),
- mScrollChildPosition.top, width, mScrollChildPosition.bottom);
- right.draw(canvas);
- }
- }
- }
-
- protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- boolean ret = super.drawChild(canvas, child, drawingTime);
-
- // We want to draw the page hints above the workspace, but below the drag view.
- if (child instanceof Workspace) {
- drawPageHints(canvas);
- }
- return ret;
- }
-
public void setBackgroundAlpha(float alpha) {
if (alpha != mBackgroundAlpha) {
mBackgroundAlpha = alpha;
diff --git a/src/com/android/launcher3/util/FlingAnimation.java b/src/com/android/launcher3/util/FlingAnimation.java
index f82038b..da8bae7 100644
--- a/src/com/android/launcher3/util/FlingAnimation.java
+++ b/src/com/android/launcher3/util/FlingAnimation.java
@@ -51,7 +51,7 @@
mFrom.top += yOffset;
mFrom.bottom -= yOffset;
- mDuration = initDuration();
+ mDuration = Math.abs(vel.y) > Math.abs(vel.x) ? initFlingUpDuration() : initFlingLeftDuration();
mAnimationTimeFraction = ((float) mDuration) / (mDuration + DRAG_END_DELAY);
}
@@ -62,7 +62,7 @@
* - Calculate a constant acceleration in x direction such that the object reaches
* {@link #mIconRect} in the given time.
*/
- protected int initDuration() {
+ protected int initFlingUpDuration() {
float sY = -mFrom.bottom;
float d = mUY * mUY + 2 * sY * MAX_ACCELERATION;
@@ -83,6 +83,34 @@
return (int) Math.round(t);
}
+ /**
+ * The fling animation is based on the following system
+ * - Apply a constant force in the x direction to causing the fling to decelerate.
+ * - The animation runs for the time taken by the object to go out of the screen.
+ * - Calculate a constant acceleration in y direction such that the object reaches
+ * {@link #mIconRect} in the given time.
+ */
+ protected int initFlingLeftDuration() {
+ float sX = -mFrom.right;
+
+ float d = mUX * mUX + 2 * sX * MAX_ACCELERATION;
+ if (d >= 0) {
+ // sX can be reached under the MAX_ACCELERATION. Use MAX_ACCELERATION for x direction.
+ mAX = MAX_ACCELERATION;
+ } else {
+ // sX is not reachable, decrease the acceleration so that sX is almost reached.
+ d = 0;
+ mAX = mUX * mUX / (2 * -sX);
+ }
+ double t = (-mUX - Math.sqrt(d)) / mAX;
+
+ float sY = -mFrom.exactCenterY() + mIconRect.exactCenterY();
+
+ // Find vertical acceleration such that: u*t + a*t*t/2 = s
+ mAY = (float) ((sY - t * mUY) * 2 / (t * t));
+ return (int) Math.round(t);
+ }
+
public final int getDuration() {
return mDuration + DRAG_END_DELAY;
}