diff options
-rw-r--r-- | quickstep/res/drawable/ic_pin.xml | 26 | ||||
-rw-r--r-- | quickstep/res/drawable/ic_split_screen.xml | 45 | ||||
-rw-r--r-- | quickstep/res/values/strings.xml | 6 | ||||
-rw-r--r-- | quickstep/src/com/android/quickstep/RecentsModel.java | 10 | ||||
-rw-r--r-- | quickstep/src/com/android/quickstep/TaskMenuView.java | 36 | ||||
-rw-r--r-- | quickstep/src/com/android/quickstep/TaskSystemShortcut.java | 98 | ||||
-rw-r--r-- | quickstep/src/com/android/quickstep/TaskView.java | 11 | ||||
-rw-r--r-- | quickstep/src/com/android/quickstep/TouchInteractionService.java | 1 |
8 files changed, 196 insertions, 37 deletions
diff --git a/quickstep/res/drawable/ic_pin.xml b/quickstep/res/drawable/ic_pin.xml new file mode 100644 index 000000000..8c799e38e --- /dev/null +++ b/quickstep/res/drawable/ic_pin.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + + <path + android:fillColor="#FFffffff" + android:pathData="M16,12L16,4l1,0L17,2L7,2l0,2l1,0l0,8l-2,2l0,2l5.2,0l0,6l1.6,0l0,-6L18,16l0,-2L16,12z"/> +</vector>
\ No newline at end of file diff --git a/quickstep/res/drawable/ic_split_screen.xml b/quickstep/res/drawable/ic_split_screen.xml new file mode 100644 index 000000000..77bd3336d --- /dev/null +++ b/quickstep/res/drawable/ic_split_screen.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="88.0dp" + android:height="88.0dp" + android:viewportWidth="88.0" + android:viewportHeight="88.0" > + + <path + android:pathData="M 32,11 + C 32,11 68,11 68,11 + 76.74,11.06 76.98,12.76 77,21 + 77.01,25.97 78.50,38.23 73.85,40.98 + 71.80,42.19 68.35,42 66,42 + 66,42 22,42 22,42 + 18.82,41.99 14.87,42.38 12.60,39.69 + 10.71,37.44 11.01,33.77 11,31 + 10.99,25.54 9.53,16.08 13.31,12.02 + 18.07,10.21 26.66,11 32,11 Z + M 32,46 + C 32,46 68,46 68,46 + 76.74,46.06 76.98,47.76 77,56 + 77.01,60.97 78.50,73.23 73.85,75.98 + 71.80,77.19 68.35,77 66,77 + 66,77 22,77 22,77 + 18.82,76.99 14.87,77.38 12.60,74.69 + 10.71,72.44 11.01,68.77 11,66 + 10.99,60.54 9.53,51.08 13.31,47.02 + 18.07,45.21 26.66,46 32,46 Z" + android:fillColor="@android:color/white" /> +</vector>
\ No newline at end of file diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index ef612268f..c2d6604b4 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -20,4 +20,10 @@ <!-- Application name --> <string name="derived_app_name" translatable="false">Quickstep</string> + + <!-- Options for recent tasks --> + <!-- Title for an option to enter split screen mode for a given app --> + <string name="recent_task_option_split_screen">Split screen</string> + <!-- Title for an option to keep an app pinned to the screen until it is unpinned --> + <string name="recent_task_option_pin">Pin</string> </resources>
\ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index 22658b29d..d10c5a640 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -24,6 +24,7 @@ import android.os.UserHandle; import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.R; +import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions; import com.android.systemui.shared.recents.model.RecentsTaskLoader; @@ -66,6 +67,7 @@ public class RecentsModel extends TaskStackChangeListener { private RecentsTaskLoadPlan mLastLoadPlan; private int mLastLoadPlanId; private int mTaskChangeId; + private ISystemUiProxy mSystemUiProxy; private RecentsModel(Context context) { mContext = context; @@ -137,4 +139,12 @@ public class RecentsModel extends TaskStackChangeListener { public RecentsTaskLoadPlan getLastLoadPlan() { return mLastLoadPlan; } + + public void setSystemUiProxy(ISystemUiProxy systemUiProxy) { + mSystemUiProxy = systemUiProxy; + } + + public ISystemUiProxy getSystemUiProxy() { + return mSystemUiProxy; + } } diff --git a/quickstep/src/com/android/quickstep/TaskMenuView.java b/quickstep/src/com/android/quickstep/TaskMenuView.java index 196a2270f..52b240002 100644 --- a/quickstep/src/com/android/quickstep/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/TaskMenuView.java @@ -40,7 +40,6 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.shortcuts.DeepShortcutView; -import com.android.systemui.shared.recents.model.Task; /** * Contains options for a recent task when long-pressing its icon. @@ -51,9 +50,10 @@ public class TaskMenuView extends AbstractFloatingView { /** Note that these will be shown in order from top to bottom, if available for the task. */ private static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] { - new TaskSystemShortcut.Widgets(), new TaskSystemShortcut.AppInfo(), - new TaskSystemShortcut.Install() + new TaskSystemShortcut.SplitScreen(), + new TaskSystemShortcut.Pin(), + new TaskSystemShortcut.Install(), }; private static final long OPEN_CLOSE_DURATION = 220; @@ -62,7 +62,6 @@ public class TaskMenuView extends AbstractFloatingView { private TextView mTaskIconAndName; private AnimatorSet mOpenCloseAnimator; private TaskView mTaskView; - private View mWidgetsOptionView; public TaskMenuView(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -133,21 +132,21 @@ public class TaskMenuView extends AbstractFloatingView { } mLauncher.getDragLayer().addView(this); mTaskView = taskView; - addMenuOptions(mTaskView.getTask()); + addMenuOptions(mTaskView); orientAroundTaskView(mTaskView); post(this::animateOpen); return true; } - private void addMenuOptions(Task task) { - Drawable icon = task.icon.getConstantState().newDrawable(); + private void addMenuOptions(TaskView taskView) { + Drawable icon = taskView.getTask().icon.getConstantState().newDrawable(); int iconSize = getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_size); icon.setBounds(0, 0, iconSize, iconSize); mTaskIconAndName.setCompoundDrawables(null, icon, null, null); - mTaskIconAndName.setText(TaskUtils.getTitle(mLauncher, task)); + mTaskIconAndName.setText(TaskUtils.getTitle(mLauncher, taskView.getTask())); for (TaskSystemShortcut menuOption : MENU_OPTIONS) { - OnClickListener onClickListener = menuOption.getOnClickListener(mLauncher, task); + OnClickListener onClickListener = menuOption.getOnClickListener(mLauncher, taskView); if (onClickListener != null) { addMenuOption(menuOption, onClickListener); } @@ -161,10 +160,6 @@ public class TaskMenuView extends AbstractFloatingView { menuOptionView.getBubbleText().setText(menuOption.labelResId); menuOptionView.setOnClickListener(onClickListener); addView(menuOptionView); - - if (menuOption instanceof TaskSystemShortcut.Widgets) { - mWidgetsOptionView = menuOptionView; - } } private void orientAroundTaskView(TaskView taskView) { @@ -231,19 +226,4 @@ public class TaskMenuView extends AbstractFloatingView { } }; } - - @Override - protected void onWidgetsBound() { - TaskSystemShortcut widgetsOption = new TaskSystemShortcut.Widgets(); - View.OnClickListener onClickListener = widgetsOption.getOnClickListener( - mLauncher, mTaskView.getTask()); - - if (onClickListener != null && mWidgetsOptionView == null) { - // We didn't have any widgets cached but now there are some, so add the option. - addMenuOption(widgetsOption, onClickListener); - } else if (onClickListener == null && mWidgetsOptionView != null) { - // No widgets exist, but we previously added the option so remove it. - removeView(mWidgetsOptionView); - } - } } diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java index 1ba7ce4e1..9200eeb06 100644 --- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java +++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java @@ -16,23 +16,37 @@ package com.android.quickstep; +import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; import android.os.UserHandle; +import android.provider.Settings; +import android.util.Log; import android.view.View; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; +import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.InstantAppResolver; +import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.ActivityOptionsCompat; + +import java.util.function.Consumer; /** * Represents a system shortcut that can be shown for a recent task. */ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut { + private static final String TAG = "TaskSystemShortcut"; + protected T mSystemShortcut; protected TaskSystemShortcut(T systemShortcut) { @@ -40,12 +54,18 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut mSystemShortcut = systemShortcut; } + protected TaskSystemShortcut(int iconResId, int labelResId) { + super(iconResId, labelResId); + } + @Override public View.OnClickListener getOnClickListener(Launcher launcher, ItemInfo itemInfo) { return null; } - public View.OnClickListener getOnClickListener(final Launcher launcher, final Task task) { + public View.OnClickListener getOnClickListener(final Launcher launcher, final TaskView view) { + Task task = view.getTask(); + ShortcutInfo dummyInfo = new ShortcutInfo(); dummyInfo.intent = new Intent(); ComponentName component = task.getTopComponent(); @@ -61,16 +81,80 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut return mSystemShortcut.getOnClickListener(launcher, dummyInfo); } + public static class AppInfo extends TaskSystemShortcut<SystemShortcut.AppInfo> { + public AppInfo() { + super(new SystemShortcut.AppInfo()); + } + } + + public static class SplitScreen extends TaskSystemShortcut { + + private Handler mHandler; + + public SplitScreen() { + super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen); + mHandler = new Handler(Looper.getMainLooper()); + } + + @Override + public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) { + if (launcher.getDeviceProfile().inMultiWindowMode()) { + return null; + } + return (v -> { + Task task = taskView.getTask(); + final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(true); + final Consumer<Boolean> resultCallback = success -> { + if (success) { + launcher.<RecentsView>getOverviewPanel().removeView(taskView); + } + }; + ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync( + task.key, options, resultCallback, mHandler); - public static class Widgets extends TaskSystemShortcut<SystemShortcut.Widgets> { - public Widgets() { - super(new SystemShortcut.Widgets()); + // TODO improve transition; see: + // DockedFirstAnimationFrameEvent + // RecentsTransitionHelper#composeDockAnimationSpec + // WindowManagerWrapper#overridePendingAppTransitionMultiThumbFuture + }); } } - public static class AppInfo extends TaskSystemShortcut<SystemShortcut.AppInfo> { - public AppInfo() { - super(new SystemShortcut.AppInfo()); + public static class Pin extends TaskSystemShortcut { + + // Same as Settings.System.LOCK_TO_APP_ENABLED, which is hidden. + // TODO use call from shared lib instead + private static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled"; + + private Handler mHandler; + + public Pin() { + super(R.drawable.ic_pin, R.string.recent_task_option_pin); + mHandler = new Handler(Looper.getMainLooper()); + } + + @Override + public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) { + ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy(); + if (sysUiProxy == null) { + return null; + } + if (Settings.System.getInt(launcher.getContentResolver(), + LOCK_TO_APP_ENABLED, 0) == 0) { + return null; + } + return view -> { + Consumer<Boolean> resultCallback = success -> { + if (success) { + try { + sysUiProxy.startScreenPinning(taskView.getTask().key.id); + } catch (RemoteException e) { + Log.w(TAG, "Failed to start screen pinning: ", e); + } + } + }; + taskView.launchTask(true, resultCallback, mHandler); + }; } } diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java index 46fcc724c..6a70e2d63 100644 --- a/quickstep/src/com/android/quickstep/TaskView.java +++ b/quickstep/src/com/android/quickstep/TaskView.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; import android.graphics.Rect; +import android.os.Handler; import android.util.AttributeSet; import android.util.Property; import android.view.View; @@ -36,7 +37,6 @@ import android.widget.ImageView; import com.android.launcher3.R; import com.android.quickstep.RecentsView.PageCallbacks; import com.android.quickstep.RecentsView.ScrollState; -import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task.TaskCallbacks; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -47,6 +47,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; /** * A task in the Recents view. @@ -127,6 +128,11 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback } public void launchTask(boolean animate) { + launchTask(animate, null, null); + } + + public void launchTask(boolean animate, Consumer<Boolean> resultCallback, + Handler resultCallbackHandler) { if (mTask != null) { final ActivityOptions opts; if (animate) { @@ -154,7 +160,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0); } ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key, - opts, null, null); + opts, resultCallback, resultCallbackHandler); } } @@ -162,6 +168,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) { mSnapshotView.setThumbnail(task, thumbnailData); mIconView.setImageDrawable(task.icon); + mIconView.setOnClickListener(icon -> TaskMenuView.showForTask(this)); mIconView.setOnLongClickListener(icon -> TaskMenuView.showForTask(this)); } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 049083217..67146ff8d 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -110,6 +110,7 @@ public class TouchInteractionService extends Service { @Override public void onBind(ISystemUiProxy iSystemUiProxy) { mISystemUiProxy = iSystemUiProxy; + mRecentsModel.setSystemUiProxy(mISystemUiProxy); } @Override |