diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 466470f3b4..521551c217 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -19,28 +19,33 @@
android:theme="@style/HomeScreenElementTheme"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"
+ android:clipToPadding="false"
android:layout_gravity="center_horizontal|bottom"
android:gravity="top">
-
-
-
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
new file mode 100644
index 0000000000..caeef50778
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 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.quickstep;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.RectEvaluator;
+import android.annotation.TargetApi;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.UserHandle;
+import android.support.annotation.BinderThread;
+import android.support.annotation.UiThread;
+import android.util.FloatProperty;
+import android.view.Choreographer;
+import android.view.Choreographer.FrameCallback;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.states.InternalStateHandler;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+@TargetApi(Build.VERSION_CODES.O)
+public class NavBarSwipeInteractionHandler extends InternalStateHandler implements FrameCallback {
+
+ private static FloatProperty SHIFT =
+ new FloatProperty("currentShift") {
+ @Override
+ public void setValue(NavBarSwipeInteractionHandler handler, float v) {
+ handler.setShift(v);
+ }
+
+ @Override
+ public Float get(NavBarSwipeInteractionHandler handler) {
+ return handler.mCurrentShift;
+ }
+ };
+
+ // The following constants need to be scaled based on density. The scaled versions will be
+ // assigned to the corresponding member variables below.
+ private static final int FLING_THRESHOLD_VELOCITY = 500;
+ private static final int MIN_FLING_VELOCITY = 250;
+
+ private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
+
+ private final Rect mSourceRect = new Rect();
+ private final Rect mTargetRect = new Rect();
+ private final Rect mCurrentRect = new Rect();
+ private final RectEvaluator mRectEvaluator = new RectEvaluator(mCurrentRect);
+
+ private final Bitmap mTaskSnapshot;
+ private final RunningTaskInfo mTaskInfo;
+
+ private Launcher mLauncher;
+ private Choreographer mChoreographer;
+ private SnapshotDragView mDragView;
+ private RecentsView mRecentsView;
+ private Hotseat mHotseat;
+
+ private float mStartDelta;
+ private float mLastDelta;
+
+ // Shift in the range of [0, 1].
+ // 0 => preview snapShot is completely visible, and hotseat is completely translated down
+ // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
+ // visible.
+ private float mCurrentShift;
+
+ // These are updated on the binder thread, and eventually picked up on doFrame
+ private float mCurrentDisplacement;
+ private boolean mTouchEnded = false;
+ private float mEndVelocity;
+
+ NavBarSwipeInteractionHandler(Bitmap taskSnapShot, RunningTaskInfo taskInfo) {
+ mTaskSnapshot = taskSnapShot;
+ mTaskInfo = taskInfo;
+ }
+
+ @Override
+ public void onLauncherResume() {
+ mStartDelta = mCurrentDisplacement;
+ mLastDelta = mStartDelta;
+ mChoreographer = Choreographer.getInstance();
+
+ scheduleNextFrame();
+ }
+
+ @Override
+ public void onNewIntent(Launcher launcher) {
+ mLauncher = launcher;
+
+ // Go immediately
+ launcher.getStateManager().goToState(LauncherState.OVERVIEW, false);
+
+ // Optimization
+ launcher.getAppsView().setVisibility(View.GONE);
+
+ mDragView = new SnapshotDragView(launcher, mTaskSnapshot);
+ launcher.getDragLayer().addView(mDragView);
+ mDragView.setPivotX(0);
+ mDragView.setPivotY(0);
+ mRecentsView = launcher.getOverviewPanel();
+ mRecentsView.scrollTo(0, 0);
+ mHotseat = launcher.getHotseat();
+ }
+
+ @BinderThread
+ public void updateDisplacement(float displacement) {
+ mCurrentDisplacement = displacement;
+ }
+
+ @BinderThread
+ public void endTouch(float endVelocity) {
+ mTouchEnded = true;
+ mEndVelocity = endVelocity;
+ }
+
+ @UiThread
+ private void scheduleNextFrame() {
+ if (!mTouchEnded) {
+ mChoreographer.postFrameCallback(this);
+ } else {
+ animateToFinalShift();
+ }
+ }
+
+ @Override
+ public void doFrame(long l) {
+ mLastDelta = mCurrentDisplacement;
+
+ float translation = Utilities.boundToRange(mStartDelta - mLastDelta, 0,
+ mHotseat.getHeight());
+ int hotseatHeight = mHotseat.getHeight();
+ float shift = hotseatHeight == 0 ? 0 : translation / hotseatHeight;
+ setShift(shift);
+ scheduleNextFrame();
+ }
+
+ @UiThread
+ private void setShift(float shift) {
+ if (mTargetRect.isEmpty()) {
+ DragLayer dl = mLauncher.getDragLayer();
+
+ // Init target rect.
+ View targetView = ((ViewGroup) mRecentsView.getChildAt(0)).getChildAt(0);
+ dl.getViewRectRelativeToSelf(targetView, mTargetRect);
+ mSourceRect.set(0, 0, dl.getWidth(), dl.getHeight());
+ }
+
+ mCurrentShift = shift;
+ int hotseatHeight = mHotseat.getHeight();
+ mHotseat.setTranslationY((1 - shift) * hotseatHeight);
+
+ mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
+
+ mDragView.setTranslationX(mCurrentRect.left);
+ mDragView.setTranslationY(mCurrentRect.top);
+ mDragView.setScaleX((float) mCurrentRect.width() / mSourceRect.width());
+ mDragView.setScaleY((float) mCurrentRect.width() / mSourceRect.width());
+ }
+
+ @UiThread
+ private void animateToFinalShift() {
+ float flingThreshold = Utilities.pxFromDp(FLING_THRESHOLD_VELOCITY,
+ mLauncher.getResources().getDisplayMetrics());
+ boolean isFling = Math.abs(mEndVelocity) > flingThreshold;
+
+ long duration = 200;
+ final float endShift;
+ if (!isFling) {
+ endShift = mCurrentShift >= MIN_PROGRESS_FOR_OVERVIEW ? 1 : 0;
+ } else {
+ endShift = mEndVelocity < 0 ? 1 : 0;
+ float minFlingVelocity = Utilities.pxFromDp(MIN_FLING_VELOCITY,
+ mLauncher.getResources().getDisplayMetrics());
+ if (Math.abs(mEndVelocity) > minFlingVelocity) {
+ float distanceToTravel = (endShift - mCurrentShift) * mHotseat.getHeight();
+
+ // we want the page's snap velocity to approximately match the velocity at
+ // which the user flings, so we scale the duration by a value near to the
+ // derivative of the scroll interpolator at zero, ie. 5. We use 4 to make
+ // it a little slower.
+ duration = 4 * Math.round(1000 * Math.abs(distanceToTravel / mEndVelocity));
+ }
+ }
+
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, SHIFT, endShift)
+ .setDuration(duration);
+ anim.setInterpolator(Interpolators.SCROLL);
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ if (Float.compare(mCurrentShift, 0) == 0) {
+ resumeLastTask();
+ } else {
+ mDragView.close(false);
+ }
+ }
+ });
+ anim.start();
+ }
+
+ @UiThread
+ private void resumeLastTask() {
+ // TODO: These should be done as part of ActivityOptions#OnAnimationStarted
+ mHotseat.setTranslationY(0);
+ mLauncher.setOnResumeCallback(() -> mDragView.close(false));
+
+ // TODO: Task key should be received from Recents model
+ TaskKey taskKey = new TaskKey(mTaskInfo.id, 0, null, UserHandle.myUserId(), 0);
+ ActivityManagerWrapper.getInstance()
+ .startActivityFromRecentsAsync(taskKey, null, null, null);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index d85de8f405..d7559daad9 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -30,6 +30,7 @@ import com.android.launcher3.R;
* A placeholder view for recents
*/
public class RecentsView extends HorizontalScrollView implements Insettable {
+
public RecentsView(Context context) {
this(context, null);
}
diff --git a/quickstep/src/com/android/quickstep/SimpleTaskView.java b/quickstep/src/com/android/quickstep/SimpleTaskView.java
new file mode 100644
index 0000000000..8425fa3ba4
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SimpleTaskView.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.quickstep;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.WindowManager;
+
+/**
+ * A simple view which keeps its size proportional to the display size
+ */
+public class SimpleTaskView extends View {
+
+ private static final Point sTempPoint = new Point();
+
+ public SimpleTaskView(Context context) {
+ super(context);
+ }
+
+ public SimpleTaskView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SimpleTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ getContext().getSystemService(WindowManager.class)
+ .getDefaultDisplay().getRealSize(sTempPoint);
+
+ int width = (int) ((float) height * sTempPoint.x / sTempPoint.y);
+ setMeasuredDimension(width, height);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/SnapshotDragView.java b/quickstep/src/com/android/quickstep/SnapshotDragView.java
new file mode 100644
index 0000000000..791fe9ff17
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SnapshotDragView.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 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.quickstep;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+
+/**
+ * Floating view which shows the task snapshot allowing it to be dragged and placed.
+ */
+public class SnapshotDragView extends AbstractFloatingView implements Insettable {
+
+ private final Launcher mLauncher;
+ private final Bitmap mSnapshot;
+
+ public SnapshotDragView(Launcher launcher, Bitmap snapshot) {
+ super(launcher, null);
+ mLauncher = launcher;
+ mSnapshot = snapshot;
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mSnapshot != null) {
+ setMeasuredDimension(mSnapshot.getWidth(), mSnapshot.getHeight());
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mSnapshot != null) {
+ canvas.drawBitmap(mSnapshot, 0, 0, null);
+ }
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ return false;
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ // We dont suupport animate.
+ mLauncher.getDragLayer().removeView(this);
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // We should probably log the weather
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_QUICKSTEP_PREVIEW) != 0;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 091ab54989..dcfa53b41e 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -15,17 +15,201 @@
*/
package com.android.quickstep;
+import static android.view.MotionEvent.INVALID_POINTER_ID;
+
+import static com.android.launcher3.states.InternalStateHandler.EXTRA_STATE_HANDLER;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityOptions;
import android.app.Service;
+import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+
+import com.android.systemui.shared.recents.IOverviewProxy;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
/**
* Service connected by system-UI for handling touch interaction.
*/
public class TouchInteractionService extends Service {
+ private static final String TAG = "TouchInteractionService";
+
+ private final IBinder mMyBinder = new IOverviewProxy.Stub() {
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ handleMotionEvent(ev);
+ }
+
+ @Override
+ public void onBind(ISystemUiProxy iSystemUiProxy) throws RemoteException {
+ mISystemUiProxy = iSystemUiProxy;
+ }
+ };
+
+ private ActivityManagerWrapper mAM;
+ private RunningTaskInfo mRunningTask;
+ private Intent mHomeIntent;
+ private ComponentName mLauncher;
+
+ private final PointF mDownPos = new PointF();
+ private final PointF mLastPos = new PointF();
+ private int mActivePointerId = INVALID_POINTER_ID;
+ private VelocityTracker mVelocityTracker;
+ private int mTouchSlop;
+ private NavBarSwipeInteractionHandler mInteractionHandler;
+
+ private ISystemUiProxy mISystemUiProxy;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mAM = ActivityManagerWrapper.getInstance();
+
+ mHomeIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setPackage(getPackageName())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ ResolveInfo info = getPackageManager().resolveActivity(mHomeIntent, 0);
+ mLauncher = new ComponentName(getPackageName(), info.activityInfo.name);
+ mHomeIntent.setComponent(mLauncher);
+ }
+
@Override
public IBinder onBind(Intent intent) {
- return null;
+ Log.d(TAG, "Touch service connected");
+ return mMyBinder;
+ }
+
+ private void handleMotionEvent(MotionEvent ev) {
+ if (ev.getActionMasked() != MotionEvent.ACTION_DOWN && mVelocityTracker == null) {
+ return;
+ }
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ mActivePointerId = ev.getPointerId(0);
+ mDownPos.set(ev.getX(), ev.getY());
+ mLastPos.set(mDownPos);
+ mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
+
+ mRunningTask = mAM.getRunningTask();
+ if (mRunningTask == null || mRunningTask.topActivity.equals(mLauncher)) {
+ // TODO: We could drive all-apps in this case. For now just ignore swipe.
+ break;
+ }
+
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ } else {
+ mVelocityTracker.clear();
+ }
+ mVelocityTracker.addMovement(ev);
+ if (mInteractionHandler != null) {
+ mInteractionHandler.endTouch(0);
+ mInteractionHandler = null;
+ }
+ break;
+ }
+ case MotionEvent.ACTION_POINTER_UP: {
+ int ptrIdx = ev.getActionIndex();
+ int ptrId = ev.getPointerId(ptrIdx);
+ if (ptrId == mActivePointerId) {
+ final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
+ mDownPos.set(
+ ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
+ ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
+ mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
+ mActivePointerId = ev.getPointerId(newPointerIdx);
+ mVelocityTracker.clear();
+ }
+ break;
+ }
+ case MotionEvent.ACTION_MOVE: {
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == INVALID_POINTER_ID) {
+ break;
+ }
+ mVelocityTracker.addMovement(ev);
+ mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+
+ float displacement = ev.getY(pointerIndex) - mDownPos.y;
+ if (mInteractionHandler == null) {
+ if (Math.abs(displacement) >= mTouchSlop) {
+ startTouchTracking();
+ }
+ } else {
+ // Move
+ mInteractionHandler.updateDisplacement(displacement);
+ }
+ break;
+ }
+ case MotionEvent.ACTION_CANCEL:
+ // TODO: Should be different than ACTION_UP
+ case MotionEvent.ACTION_UP: {
+
+ endInteraction();
+ break;
+ }
+ }
+ }
+
+ private void startTouchTracking() {
+ mInteractionHandler = new NavBarSwipeInteractionHandler(getCurrentTaskSnapshot(), mRunningTask);
+
+ Bundle extras = new Bundle();
+ extras.putBinder(EXTRA_STATE_HANDLER, mInteractionHandler);
+ Intent homeIntent = new Intent(mHomeIntent).putExtras(extras);
+
+ // TODO: Call ActivityManager#startRecentsActivity instead, so that the system knows that
+ // recents was started and not Home.
+ startActivity(homeIntent,
+ ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle());
+ }
+
+ private void endInteraction() {
+ if (mInteractionHandler != null) {
+ mVelocityTracker.computeCurrentVelocity(1000,
+ ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
+
+ mInteractionHandler.endTouch(mVelocityTracker.getXVelocity(mActivePointerId));
+ mInteractionHandler = null;
+ }
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+
+ private Bitmap getCurrentTaskSnapshot() {
+ if (mISystemUiProxy == null) {
+ Log.e(TAG, "Never received systemUIProxy");
+ return null;
+ }
+ Display display = getSystemService(WindowManager.class).getDefaultDisplay();
+ Point size = new Point();
+ display.getRealSize(size);
+
+ // TODO: We are using some hardcoded layers for now, to best approximate the activity layers
+ try {
+ return mISystemUiProxy.screenshot(new Rect(), size.x, size.y, 0, 100000, false,
+ display.getRotation());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error capturing snapshot", e);
+ return null;
+ }
}
}
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 62e0fb1bcd..26024e5310 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -20,7 +20,6 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.IntDef;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
@@ -42,7 +41,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
TYPE_ACTION_POPUP,
TYPE_WIDGETS_BOTTOM_SHEET,
TYPE_WIDGET_RESIZE_FRAME,
- TYPE_WIDGETS_FULL_SHEET
+ TYPE_WIDGETS_FULL_SHEET,
+ TYPE_QUICKSTEP_PREVIEW
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
@@ -51,9 +51,11 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_WIDGETS_BOTTOM_SHEET = 1 << 2;
public static final int TYPE_WIDGET_RESIZE_FRAME = 1 << 3;
public static final int TYPE_WIDGETS_FULL_SHEET = 1 << 4;
+ public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 5;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
- | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET;
+ | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
+ | TYPE_QUICKSTEP_PREVIEW;
protected boolean mIsOpen;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index baed44d75d..b1b3452e4b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -63,6 +63,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
@@ -123,6 +124,7 @@ import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.states.AllAppsState;
+import com.android.launcher3.states.InternalStateHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -1405,6 +1407,7 @@ public class Launcher extends BaseActivity
});
}
}
+ InternalStateHandler.handleIntent(this, intent);
TraceHelper.endSection("NEW_INTENT");
}
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
new file mode 100644
index 0000000000..a90ed36aa9
--- /dev/null
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 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.states;
+
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.Launcher.OnResumeCallback;
+
+/**
+ * Utility class to sending state handling logic to Launcher from within the same process
+ */
+public abstract class InternalStateHandler extends Binder implements OnResumeCallback {
+
+ public static final String EXTRA_STATE_HANDLER = "launcher.state_handler";
+
+ public abstract void onNewIntent(Launcher launcher);
+
+ public static void handleIntent(Launcher launcher, Intent intent) {
+ IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER);
+ if (stateBinder instanceof InternalStateHandler) {
+ InternalStateHandler handler = (InternalStateHandler) stateBinder;
+ launcher.setOnResumeCallback(handler);
+ handler.onNewIntent(launcher);
+ }
+ intent.getExtras().remove(EXTRA_STATE_HANDLER);
+ }
+}