Merge "Adding dnd to/from freeform workspaces."
This commit is contained in:
@@ -110,7 +110,8 @@ public class RecentsConfiguration {
|
||||
void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
|
||||
// Only update resources that can change after the first load, either through developer
|
||||
// settings or via multi window
|
||||
lockToAppEnabled = ssp.getSystemSetting(context, Settings.System.LOCK_TO_APP_ENABLED) != 0;
|
||||
lockToAppEnabled = !ssp.hasFreeformWorkspaceSupport() &&
|
||||
ssp.getSystemSetting(context, Settings.System.LOCK_TO_APP_ENABLED) != 0;
|
||||
hasDockedTasks = ssp.hasDockedTask();
|
||||
|
||||
// Recompute some values based on the given state, since we can not rely on the resource
|
||||
|
||||
@@ -514,7 +514,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
|
||||
reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
|
||||
|
||||
// Update the destination rect
|
||||
mDummyStackView.updateMinMaxScrollForStack(stack);
|
||||
mDummyStackView.updateLayoutForStack(stack);
|
||||
final Task toTask = new Task();
|
||||
final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
|
||||
topTask.id, toTask);
|
||||
@@ -696,7 +696,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
|
||||
TaskStack stack = sInstanceLoadPlan.getTaskStack();
|
||||
|
||||
// Prepare the dummy stack for the transition
|
||||
mDummyStackView.updateMinMaxScrollForStack(stack);
|
||||
mDummyStackView.updateLayoutForStack(stack);
|
||||
TaskStackLayoutAlgorithm.VisibilityReport stackVr =
|
||||
mDummyStackView.computeStackVisibilityReport();
|
||||
boolean hasRecentTasks = stack.getTaskCount() > 0;
|
||||
|
||||
@@ -549,7 +549,7 @@ public class EventBus extends BroadcastReceiver {
|
||||
InvocationTargetException|
|
||||
InstantiationException|
|
||||
IllegalAccessException e) {
|
||||
Log.e(TAG, "Failed to create InterprocessEvent", e);
|
||||
Log.e(TAG, "Failed to create InterprocessEvent", e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,9 +746,9 @@ public class EventBus extends BroadcastReceiver {
|
||||
Log.e(TAG, "Failed to deliver event to null subscriber");
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(TAG, "Failed to invoke method", e);
|
||||
Log.e(TAG, "Failed to invoke method", e.getCause());
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
Log.e(TAG, "Failed to invoke method", e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,18 +18,18 @@ package com.android.systemui.recents.events.ui.dragndrop;
|
||||
|
||||
import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskStack;
|
||||
import com.android.systemui.recents.views.DropTarget;
|
||||
|
||||
/**
|
||||
* This event is sent when a user drag enters or exits a dock region.
|
||||
* This event is sent when a user drags in/out of a drop target.
|
||||
*/
|
||||
public class DragDockStateChangedEvent extends EventBus.Event {
|
||||
public class DragDropTargetChangedEvent extends EventBus.Event {
|
||||
|
||||
public final Task task;
|
||||
public final TaskStack.DockState dockState;
|
||||
public final DropTarget dropTarget;
|
||||
|
||||
public DragDockStateChangedEvent(Task task, TaskStack.DockState dockState) {
|
||||
public DragDropTargetChangedEvent(Task task, DropTarget dropTarget) {
|
||||
this.task = task;
|
||||
this.dockState = dockState;
|
||||
this.dropTarget = dropTarget;
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,8 @@ package com.android.systemui.recents.events.ui.dragndrop;
|
||||
import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskStack;
|
||||
import com.android.systemui.recents.views.DragView;
|
||||
import com.android.systemui.recents.views.DropTarget;
|
||||
import com.android.systemui.recents.views.TaskView;
|
||||
|
||||
/**
|
||||
@@ -31,15 +31,15 @@ public class DragEndEvent extends EventBus.Event {
|
||||
public final Task task;
|
||||
public final TaskView taskView;
|
||||
public final DragView dragView;
|
||||
public final TaskStack.DockState dockState;
|
||||
public final DropTarget dropTarget;
|
||||
public final ReferenceCountedTrigger postAnimationTrigger;
|
||||
|
||||
public DragEndEvent(Task task, TaskView taskView, DragView dragView,
|
||||
TaskStack.DockState dockState, ReferenceCountedTrigger postAnimationTrigger) {
|
||||
public DragEndEvent(Task task, TaskView taskView, DragView dragView, DropTarget dropTarget,
|
||||
ReferenceCountedTrigger postAnimationTrigger) {
|
||||
this.task = task;
|
||||
this.taskView = taskView;
|
||||
this.dragView = dragView;
|
||||
this.dockState = dockState;
|
||||
this.dropTarget = dropTarget;
|
||||
this.postAnimationTrigger = postAnimationTrigger;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.systemui.recents.events.ui.dragndrop;
|
||||
|
||||
import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.views.RecentsViewTouchHandler;
|
||||
|
||||
/**
|
||||
* This event is sent by the drag manager when it requires drop targets to register themselves for
|
||||
* the current drag gesture.
|
||||
*/
|
||||
public class DragStartInitializeDropTargetsEvent extends EventBus.Event {
|
||||
|
||||
public final Task task;
|
||||
public final RecentsViewTouchHandler handler;
|
||||
|
||||
public DragStartInitializeDropTargetsEvent(Task task, RecentsViewTouchHandler handler) {
|
||||
this.task = task;
|
||||
this.handler = handler;
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,7 @@ public class SystemServicesProxy {
|
||||
Display mDisplay;
|
||||
String mRecentsPackage;
|
||||
ComponentName mAssistComponent;
|
||||
boolean mHasFreeformWorkspaceSupport;
|
||||
|
||||
Bitmap mDummyIcon;
|
||||
int mDummyThumbnailWidth;
|
||||
@@ -123,6 +124,8 @@ public class SystemServicesProxy {
|
||||
mUm = UserManager.get(context);
|
||||
mDisplay = mWm.getDefaultDisplay();
|
||||
mRecentsPackage = context.getPackageName();
|
||||
mHasFreeformWorkspaceSupport = false && mPm.hasSystemFeature(
|
||||
PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
|
||||
|
||||
// Get the dummy thumbnail width/heights
|
||||
Resources res = context.getResources();
|
||||
@@ -241,7 +244,7 @@ public class SystemServicesProxy {
|
||||
public boolean hasFreeformWorkspaceSupport() {
|
||||
if (mPm == null) return false;
|
||||
|
||||
return mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
|
||||
return mHasFreeformWorkspaceSupport;
|
||||
}
|
||||
|
||||
/** Returns whether the recents is currently running */
|
||||
@@ -411,6 +414,19 @@ public class SystemServicesProxy {
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a task into another stack.
|
||||
*/
|
||||
public void moveTaskToStack(int taskId, int stackId) {
|
||||
if (mIam == null) return;
|
||||
|
||||
try {
|
||||
mIam.positionTaskInStack(taskId, stackId, 0);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** Moves a task to the front with the specified activity options. */
|
||||
public void moveTaskToFront(int taskId, ActivityOptions opts) {
|
||||
if (mAm == null) return;
|
||||
|
||||
@@ -22,6 +22,8 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import com.android.systemui.recents.Recents;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -165,7 +167,9 @@ public class Task {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
/** Updates the stack id of this task. */
|
||||
/**
|
||||
* Updates the stack id of this task.
|
||||
*/
|
||||
public void setStackId(int stackId) {
|
||||
key.stackId = stackId;
|
||||
if (mCb != null) {
|
||||
@@ -173,10 +177,12 @@ public class Task {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this task is on the freeform task stack.
|
||||
*/
|
||||
public boolean isFreeformTask() {
|
||||
// Temporarily disable:
|
||||
return false;
|
||||
// return SystemServicesProxy.isFreeformStack(key.stackId);
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId);
|
||||
}
|
||||
|
||||
/** Notifies the callback listeners that this task has been loaded */
|
||||
@@ -210,7 +216,7 @@ public class Task {
|
||||
if (group != null) {
|
||||
groupAffiliation = Integer.toString(group.affiliation);
|
||||
}
|
||||
return "Task (" + groupAffiliation + "): " + key.getComponent().getPackageName() +
|
||||
return "Task (" + groupAffiliation + "): " + key +
|
||||
" [" + super.toString() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,21 @@
|
||||
package com.android.systemui.recents.model;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.util.Log;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.Constants;
|
||||
import com.android.systemui.recents.Recents;
|
||||
import com.android.systemui.recents.misc.NamedCounter;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.views.DropTarget;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -40,6 +43,8 @@ import java.util.Random;
|
||||
|
||||
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
|
||||
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
|
||||
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
|
||||
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
|
||||
|
||||
|
||||
/**
|
||||
@@ -54,9 +59,13 @@ interface TaskFilter {
|
||||
* A list of filtered tasks.
|
||||
*/
|
||||
class FilteredTaskList {
|
||||
ArrayList<Task> mTasks = new ArrayList<Task>();
|
||||
ArrayList<Task> mFilteredTasks = new ArrayList<Task>();
|
||||
HashMap<Task.TaskKey, Integer> mTaskIndices = new HashMap<Task.TaskKey, Integer>();
|
||||
|
||||
private static final String TAG = "FilteredTaskList";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
ArrayList<Task> mTasks = new ArrayList<>();
|
||||
ArrayList<Task> mFilteredTasks = new ArrayList<>();
|
||||
HashMap<Task.TaskKey, Integer> mTaskIndices = new HashMap<>();
|
||||
TaskFilter mFilter;
|
||||
|
||||
/** Sets the task filter, saving the current touch state */
|
||||
@@ -93,6 +102,25 @@ class FilteredTaskList {
|
||||
updateFilteredTasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the given task.
|
||||
*/
|
||||
public void moveTaskToStack(Task task, int insertIndex, int newStackId) {
|
||||
int taskIndex = indexOf(task);
|
||||
if (taskIndex != insertIndex) {
|
||||
mTasks.remove(taskIndex);
|
||||
if (taskIndex < insertIndex) {
|
||||
insertIndex--;
|
||||
}
|
||||
mTasks.add(insertIndex, task);
|
||||
}
|
||||
|
||||
// Update the stack id now, after we've moved the task, and before we update the
|
||||
// filtered tasks
|
||||
task.setStackId(newStackId);
|
||||
updateFilteredTasks();
|
||||
}
|
||||
|
||||
/** Sets the list of tasks */
|
||||
void set(List<Task> tasks) {
|
||||
mTasks.clear();
|
||||
@@ -187,16 +215,21 @@ public class TaskStack {
|
||||
}
|
||||
|
||||
|
||||
public enum DockState {
|
||||
NONE(-1, 96, null, null, null),
|
||||
public enum DockState implements DropTarget {
|
||||
NONE(-1, 96, null, null),
|
||||
LEFT(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, 192,
|
||||
new RectF(0, 0, 0.3f, 1), new RectF(0, 0, 0.3f, 1), new RectF(0.7f, 0, 1, 1)),
|
||||
new RectF(0, 0, 0.25f, 1), new RectF(0, 0, 0.25f, 1)),
|
||||
TOP(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, 192,
|
||||
new RectF(0, 0, 1, 0.3f), new RectF(0, 0, 1, 0.3f), new RectF(0, 0.7f, 1, 1)),
|
||||
new RectF(0, 0, 1, 0.25f), new RectF(0, 0, 1, 0.25f)),
|
||||
RIGHT(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, 192,
|
||||
new RectF(0.7f, 0, 1, 1), new RectF(0.7f, 0, 1, 1), new RectF(0, 0, 0.3f, 1)),
|
||||
new RectF(0.75f, 0, 1, 1), new RectF(0.75f, 0, 1, 1)),
|
||||
BOTTOM(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, 192,
|
||||
new RectF(0, 0.7f, 1, 1), new RectF(0, 0.7f, 1, 1), new RectF(0, 0, 1, 0.3f));
|
||||
new RectF(0, 0.75f, 1, 1), new RectF(0, 0.75f, 1, 1));
|
||||
|
||||
@Override
|
||||
public boolean acceptsDrop(int x, int y, int width, int height) {
|
||||
return touchAreaContainsPoint(width, height, x, y);
|
||||
}
|
||||
|
||||
// Represents the view state of this dock state
|
||||
public class ViewState {
|
||||
@@ -229,20 +262,17 @@ public class TaskStack {
|
||||
public final ViewState viewState;
|
||||
private final RectF dockArea;
|
||||
private final RectF touchArea;
|
||||
private final RectF stackArea;
|
||||
|
||||
/**
|
||||
* @param createMode used to pass to ActivityManager to dock the task
|
||||
* @param touchArea the area in which touch will initiate this dock state
|
||||
* @param stackArea the area for the stack if a task is docked
|
||||
* @param dockArea the visible dock area
|
||||
*/
|
||||
DockState(int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea,
|
||||
RectF stackArea) {
|
||||
DockState(int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea) {
|
||||
this.createMode = createMode;
|
||||
this.viewState = new ViewState(dockAreaAlpha);
|
||||
this.dockArea = dockArea;
|
||||
this.touchArea = touchArea;
|
||||
this.stackArea = stackArea;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,18 +294,6 @@ public class TaskStack {
|
||||
return new Rect((int) (dockArea.left * width), (int) (dockArea.top * height),
|
||||
(int) (dockArea.right * width), (int) (dockArea.bottom * height));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stack bounds with the given {@param width} and {@param height}.
|
||||
*/
|
||||
public Rect getStackBounds(Rect stackRect) {
|
||||
int width = stackRect.width();
|
||||
int height = stackRect.height();
|
||||
return new Rect((int) (stackRect.left + stackArea.left * width),
|
||||
(int) (stackRect.top + stackArea.top * height),
|
||||
(int) (stackRect.left + (stackArea.right - stackArea.left) * width),
|
||||
(int) (stackRect.top + (stackArea.bottom - stackArea.top) * height));
|
||||
}
|
||||
}
|
||||
|
||||
// The task offset to apply to a task id as a group affiliation
|
||||
@@ -308,6 +326,29 @@ public class TaskStack {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the given task to either the front of the freeform workspace or the stack.
|
||||
*/
|
||||
public void moveTaskToStack(Task task, int newStackId) {
|
||||
// Find the index to insert into
|
||||
ArrayList<Task> taskList = mTaskList.getTasks();
|
||||
int taskCount = taskList.size();
|
||||
if (!task.isFreeformTask() && (newStackId == FREEFORM_WORKSPACE_STACK_ID)) {
|
||||
// Insert freeform tasks at the front
|
||||
mTaskList.moveTaskToStack(task, taskCount, newStackId);
|
||||
} else if (task.isFreeformTask() && (newStackId == FULLSCREEN_WORKSPACE_STACK_ID)) {
|
||||
// Insert after the first stacked task
|
||||
int insertIndex = 0;
|
||||
for (int i = taskCount - 1; i >= 0; i--) {
|
||||
if (!taskList.get(i).isFreeformTask()) {
|
||||
insertIndex = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mTaskList.moveTaskToStack(task, insertIndex, newStackId);
|
||||
}
|
||||
}
|
||||
|
||||
/** Does the actual work associated with removing the task. */
|
||||
void removeTaskImpl(Task t) {
|
||||
// Remove the task from the list
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.systemui.recents.views;
|
||||
|
||||
/**
|
||||
* Represents a drop target for a drag gesture.
|
||||
*/
|
||||
public interface DropTarget {
|
||||
|
||||
/**
|
||||
* Returns whether this target can accept this drop. The x,y are relative to the top level
|
||||
* RecentsView, and the width/height are of the RecentsView.
|
||||
*/
|
||||
boolean acceptsDrop(int x, int y, int width, int height);
|
||||
}
|
||||
@@ -111,6 +111,11 @@ public class FreeformWorkspaceLayoutAlgorithm {
|
||||
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
|
||||
transformOut.visible = true;
|
||||
transformOut.p = 0;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "getTransform: " + task.key + ", " + transformOut);
|
||||
}
|
||||
|
||||
return transformOut;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.systemui.recents.views;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -51,7 +50,7 @@ import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
|
||||
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
|
||||
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
@@ -314,9 +313,10 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
}
|
||||
|
||||
if (mDragView != null) {
|
||||
Rect taskRect = mTaskStackView.mLayoutAlgorithm.mTaskRect;
|
||||
mDragView.measure(
|
||||
MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
|
||||
MeasureSpec.makeMeasureSpec(taskRect.width(), MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec(taskRect.height(), MeasureSpec.AT_MOST));
|
||||
}
|
||||
|
||||
setMeasuredDimension(width, height);
|
||||
@@ -765,52 +765,76 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
TaskStack.DockState.NONE.viewState.dockAreaAlpha);
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragDockStateChangedEvent event) {
|
||||
if (event.dockState == TaskStack.DockState.NONE) {
|
||||
public final void onBusEvent(DragDropTargetChangedEvent event) {
|
||||
if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) {
|
||||
updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
|
||||
TaskStack.DockState.NONE.viewState.dockAreaAlpha);
|
||||
} else {
|
||||
updateVisibleDockRegions(new TaskStack.DockState[] {event.dockState}, -1);
|
||||
final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
|
||||
updateVisibleDockRegions(new TaskStack.DockState[] {dockState}, -1);
|
||||
}
|
||||
}
|
||||
|
||||
public final void onBusEvent(final DragEndEvent event) {
|
||||
event.postAnimationTrigger.increment();
|
||||
event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
final Runnable cleanUpRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Remove the drag view
|
||||
removeView(mDragView);
|
||||
mDragView = null;
|
||||
updateVisibleDockRegions(null, -1);
|
||||
|
||||
// Dock the new task if we are hovering over a valid dock state
|
||||
if (event.dockState != TaskStack.DockState.NONE) {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
ssp.startTaskInDockedMode(event.task.key.id, event.dockState.createMode);
|
||||
launchTask(event.task, null, INVALID_STACK_ID);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (event.dockState == TaskStack.DockState.NONE) {
|
||||
// Animate the alpha back to what it was before
|
||||
Rect taskBounds = mTaskStackView.getStackAlgorithm().getUntransformedTaskViewBounds();
|
||||
int left = taskBounds.left + (int) ((1f - event.taskView.getScaleX()) * taskBounds.width()) / 2;
|
||||
int top = taskBounds.top + (int) ((1f - event.taskView.getScaleY()) * taskBounds.height()) / 2;
|
||||
};
|
||||
|
||||
// Animate the overlay alpha back to 0
|
||||
updateVisibleDockRegions(null, -1);
|
||||
|
||||
if (event.dropTarget == null) {
|
||||
// No drop targets for hit, so just animate the task back to its place
|
||||
event.postAnimationTrigger.increment();
|
||||
event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
cleanUpRunnable.run();
|
||||
}
|
||||
});
|
||||
// Animate the task back to where it was before then clean up afterwards
|
||||
TaskViewTransform taskTransform = new TaskViewTransform();
|
||||
TaskStackLayoutAlgorithm layoutAlgorithm = mTaskStackView.getStackAlgorithm();
|
||||
layoutAlgorithm.getStackTransform(event.task,
|
||||
mTaskStackView.getScroller().getStackScroll(), taskTransform, null);
|
||||
event.dragView.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.translationX(left + event.taskView.getTranslationX())
|
||||
.translationY(top + event.taskView.getTranslationY())
|
||||
.scaleX(taskTransform.scale)
|
||||
.scaleY(taskTransform.scale)
|
||||
.translationX((layoutAlgorithm.mTaskRect.left - event.dragView.getLeft())
|
||||
+ taskTransform.translationX)
|
||||
.translationY((layoutAlgorithm.mTaskRect.top - event.dragView.getTop())
|
||||
+ taskTransform.translationY)
|
||||
.setDuration(175)
|
||||
.setInterpolator(mFastOutSlowInInterpolator)
|
||||
.withEndAction(event.postAnimationTrigger.decrementAsRunnable())
|
||||
.start();
|
||||
|
||||
// Animate the overlay alpha back to 0
|
||||
updateVisibleDockRegions(null, -1);
|
||||
} else if (event.dropTarget instanceof TaskStack.DockState) {
|
||||
final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
|
||||
|
||||
// For now, just remove the drag view and the original task
|
||||
// TODO: Animate the task to the drop target rect before launching it above
|
||||
cleanUpRunnable.run();
|
||||
|
||||
// Dock the task and launch it
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode);
|
||||
launchTask(event.task, null, INVALID_STACK_ID);
|
||||
|
||||
} else {
|
||||
event.postAnimationTrigger.decrement();
|
||||
// We dropped on another drop target, so just add the cleanup to the post animation
|
||||
// trigger
|
||||
event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
cleanUpRunnable.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,16 @@ import android.view.MotionEvent;
|
||||
import com.android.systemui.recents.Recents;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
|
||||
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the dock regions for each orientation.
|
||||
@@ -52,7 +55,10 @@ class DockRegion {
|
||||
/**
|
||||
* Handles touch events for a RecentsView.
|
||||
*/
|
||||
class RecentsViewTouchHandler {
|
||||
public class RecentsViewTouchHandler {
|
||||
|
||||
private static final String TAG = "RecentsViewTouchHandler";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private RecentsView mRv;
|
||||
|
||||
@@ -62,12 +68,21 @@ class RecentsViewTouchHandler {
|
||||
|
||||
private Point mDownPos = new Point();
|
||||
private boolean mDragging;
|
||||
private TaskStack.DockState mLastDockState = TaskStack.DockState.NONE;
|
||||
|
||||
private DropTarget mLastDropTarget;
|
||||
private ArrayList<DropTarget> mDropTargets = new ArrayList<>();
|
||||
|
||||
public RecentsViewTouchHandler(RecentsView rv) {
|
||||
mRv = rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new drop target for the current drag only.
|
||||
*/
|
||||
public void registerDropTargetForCurrentDrag(DropTarget target) {
|
||||
mDropTargets.add(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preferred dock states for the current orientation.
|
||||
*/
|
||||
@@ -101,11 +116,24 @@ class RecentsViewTouchHandler {
|
||||
mDragTask = event.task;
|
||||
mTaskView = event.taskView;
|
||||
mDragView = event.dragView;
|
||||
mDropTargets.clear();
|
||||
|
||||
float x = mDownPos.x - mDragView.getTopLeftOffset().x;
|
||||
float y = mDownPos.y - mDragView.getTopLeftOffset().y;
|
||||
mDragView.setTranslationX(x);
|
||||
mDragView.setTranslationY(y);
|
||||
|
||||
RecentsConfiguration config = Recents.getConfiguration();
|
||||
if (!config.hasDockedTasks) {
|
||||
// Add the dock state drop targets (these take priority)
|
||||
TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
|
||||
for (TaskStack.DockState dockState : dockStates) {
|
||||
registerDropTargetForCurrentDrag(dockState);
|
||||
}
|
||||
}
|
||||
|
||||
// Request other drop targets to register themselves
|
||||
EventBus.getDefault().send(new DragStartInitializeDropTargetsEvent(event.task, this));
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragEndEvent event) {
|
||||
@@ -113,7 +141,7 @@ class RecentsViewTouchHandler {
|
||||
mDragTask = null;
|
||||
mTaskView = null;
|
||||
mDragView = null;
|
||||
mLastDockState = TaskStack.DockState.NONE;
|
||||
mLastDropTarget = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,8 +149,6 @@ class RecentsViewTouchHandler {
|
||||
* @param ev
|
||||
*/
|
||||
private void handleTouchEvent(MotionEvent ev) {
|
||||
boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
|
||||
Configuration.ORIENTATION_LANDSCAPE;
|
||||
int action = ev.getAction();
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
@@ -137,20 +163,17 @@ class RecentsViewTouchHandler {
|
||||
float x = evX - mDragView.getTopLeftOffset().x;
|
||||
float y = evY - mDragView.getTopLeftOffset().y;
|
||||
|
||||
// Update the dock state
|
||||
TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
|
||||
TaskStack.DockState foundDockState = TaskStack.DockState.NONE;
|
||||
for (int i = dockStates.length - 1; i >= 0; i--) {
|
||||
TaskStack.DockState state = dockStates[i];
|
||||
if (state.touchAreaContainsPoint(width, height, evX, evY)) {
|
||||
foundDockState = state;
|
||||
DropTarget currentDropTarget = null;
|
||||
for (DropTarget target : mDropTargets) {
|
||||
if (target.acceptsDrop((int) evX, (int) evY, width, height)) {
|
||||
currentDropTarget = target;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mLastDockState != foundDockState) {
|
||||
mLastDockState = foundDockState;
|
||||
EventBus.getDefault().send(new DragDockStateChangedEvent(mDragTask,
|
||||
foundDockState));
|
||||
if (mLastDropTarget != currentDropTarget) {
|
||||
mLastDropTarget = currentDropTarget;
|
||||
EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask,
|
||||
currentDropTarget));
|
||||
}
|
||||
|
||||
mDragView.setTranslationX(x);
|
||||
@@ -165,7 +188,7 @@ class RecentsViewTouchHandler {
|
||||
mRv.getContext(), null, null, null);
|
||||
postAnimationTrigger.increment();
|
||||
EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, mDragView,
|
||||
mLastDockState, postAnimationTrigger));
|
||||
mLastDropTarget, postAnimationTrigger));
|
||||
postAnimationTrigger.decrement();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -63,23 +63,6 @@ public class TaskStackLayoutAlgorithm {
|
||||
|
||||
Context mContext;
|
||||
|
||||
/*
|
||||
+-------------------+
|
||||
| SEARCH |
|
||||
+-------------------+
|
||||
|+-----------------+|
|
||||
|| FREEFORM ||
|
||||
|| ||
|
||||
|| ||
|
||||
|+-----------------+|
|
||||
| +-----------+ |
|
||||
| +---------------+ |
|
||||
| | | |
|
||||
|+-----------------+|
|
||||
|| STACK ||
|
||||
+-------------------+
|
||||
*/
|
||||
|
||||
// The task bounds (untransformed) for layout. This rect is anchored at mTaskRoot.
|
||||
public Rect mTaskRect = new Rect();
|
||||
// The freeform workspace bounds, inset from the top by the search bar, and is a fixed height
|
||||
@@ -165,8 +148,8 @@ public class TaskStackLayoutAlgorithm {
|
||||
}, new ParametricCurve.ParametricCurveFunction() {
|
||||
@Override
|
||||
public float f(float p) {
|
||||
// Don't scale when there are freeform tasks
|
||||
if (mNumFreeformTasks > 0) {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
if (ssp.hasFreeformWorkspaceSupport()) {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
@@ -196,6 +179,7 @@ public class TaskStackLayoutAlgorithm {
|
||||
*/
|
||||
public void initialize(Rect taskStackBounds) {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
|
||||
RecentsConfiguration config = Recents.getConfiguration();
|
||||
int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
|
||||
int heightPadding = mContext.getResources().getDimensionPixelSize(
|
||||
@@ -262,9 +246,7 @@ public class TaskStackLayoutAlgorithm {
|
||||
* in the stack.
|
||||
*/
|
||||
void update(TaskStack stack) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "update");
|
||||
}
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
|
||||
// Clear the progress map
|
||||
mTaskProgressMap.clear();
|
||||
@@ -292,10 +274,10 @@ public class TaskStackLayoutAlgorithm {
|
||||
mNumStackTasks = stackTasks.size();
|
||||
mNumFreeformTasks = freeformTasks.size();
|
||||
|
||||
float pAtBackMostTaskTop = 0;
|
||||
float pAtFrontMostTaskTop = pAtBackMostTaskTop;
|
||||
if (!stackTasks.isEmpty()) {
|
||||
// Update the for each task from back to front.
|
||||
float pAtBackMostTaskTop = 0;
|
||||
float pAtFrontMostTaskTop = pAtBackMostTaskTop;
|
||||
int taskCount = stackTasks.size();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
Task task = stackTasks.get(i);
|
||||
@@ -307,7 +289,7 @@ public class TaskStackLayoutAlgorithm {
|
||||
|
||||
if (i < (taskCount - 1)) {
|
||||
// Increment the peek height
|
||||
float pPeek = task.group.isFrontMostTask(task) ?
|
||||
float pPeek = task.group == null || task.group.isFrontMostTask(task) ?
|
||||
mBetweenAffiliationPOffset : mWithinAffiliationPOffset;
|
||||
pAtFrontMostTaskTop += pPeek;
|
||||
}
|
||||
@@ -318,10 +300,12 @@ public class TaskStackLayoutAlgorithm {
|
||||
// Set the stack end scroll progress to the point at which the bottom of the front-most
|
||||
// task is aligned to the bottom of the stack
|
||||
mMaxScrollP = alignToStackBottom(pAtFrontMostTaskTop,
|
||||
mStackBottomPOffset + mTaskHeightPOffset);
|
||||
mStackBottomPOffset + (ssp.hasFreeformWorkspaceSupport() ?
|
||||
mTaskHalfHeightPOffset : mTaskHeightPOffset));
|
||||
// Basically align the back-most task such that the last two tasks would be visible
|
||||
mMinScrollP = alignToStackBottom(pAtBackMostTaskTop,
|
||||
mStackBottomPOffset + mTaskHeightPOffset);
|
||||
mStackBottomPOffset + (ssp.hasFreeformWorkspaceSupport() ?
|
||||
mTaskHalfHeightPOffset : mTaskHeightPOffset));
|
||||
} else {
|
||||
// When there is a single item, then just make all the stack progresses the same
|
||||
mMinScrollP = mMaxScrollP = 0;
|
||||
@@ -379,7 +363,7 @@ public class TaskStackLayoutAlgorithm {
|
||||
if (progress < 0) {
|
||||
break;
|
||||
}
|
||||
boolean isFrontMostTaskInGroup = task.group.isFrontMostTask(task);
|
||||
boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task);
|
||||
if (isFrontMostTaskInGroup) {
|
||||
float scaleAtP = sCurve.pToScale(progress);
|
||||
int scaleYOffsetAtP = (int) (((1f - scaleAtP) * taskHeight) / 2);
|
||||
@@ -432,12 +416,13 @@ public class TaskStackLayoutAlgorithm {
|
||||
/** Update/get the transform */
|
||||
public TaskViewTransform getStackTransform(float taskProgress, float stackScroll,
|
||||
TaskViewTransform transformOut, TaskViewTransform prevTransform) {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
|
||||
if (mNumStackTasks == 1) {
|
||||
if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
|
||||
// Center the task in the stack, changing the scale will not follow the curve, but just
|
||||
// modulate some values directly
|
||||
float pTaskRelative = mMinScrollP - stackScroll;
|
||||
float scale = (mNumFreeformTasks > 0) ? 1f : SINGLE_TASK_SCALE;
|
||||
float scale = ssp.hasFreeformWorkspaceSupport() ? 1f : SINGLE_TASK_SCALE;
|
||||
int topOffset = (mCurrentStackRect.top - mTaskRect.top) +
|
||||
(mCurrentStackRect.height() - mTaskRect.height()) / 2;
|
||||
transformOut.scale = scale;
|
||||
|
||||
@@ -30,6 +30,8 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.Constants;
|
||||
@@ -42,6 +44,10 @@ import com.android.systemui.recents.events.activity.PackagesChangedEvent;
|
||||
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
|
||||
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
|
||||
import com.android.systemui.recents.events.ui.UserInteractionEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
|
||||
import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
|
||||
import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
|
||||
import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
|
||||
@@ -58,6 +64,8 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
|
||||
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
|
||||
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
|
||||
|
||||
|
||||
@@ -110,8 +118,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
LayoutInflater mInflater;
|
||||
boolean mLayersDisabled;
|
||||
|
||||
Interpolator mFastOutSlowInInterpolator;
|
||||
|
||||
// A convenience update listener to request updating clipping of tasks
|
||||
ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
|
||||
private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
|
||||
new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
@@ -119,6 +129,21 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
};
|
||||
|
||||
// The drop targets for a task drag
|
||||
private DropTarget mFreeformWorkspaceDropTarget = new DropTarget() {
|
||||
@Override
|
||||
public boolean acceptsDrop(int x, int y, int width, int height) {
|
||||
return mLayoutAlgorithm.mFreeformRect.contains(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
private DropTarget mStackDropTarget = new DropTarget() {
|
||||
@Override
|
||||
public boolean acceptsDrop(int x, int y, int width, int height) {
|
||||
return mLayoutAlgorithm.mCurrentStackRect.contains(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
public TaskStackView(Context context, TaskStack stack) {
|
||||
super(context);
|
||||
// Set the stack first
|
||||
@@ -130,6 +155,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm);
|
||||
mStackScroller.setCallbacks(this);
|
||||
mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
|
||||
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
|
||||
com.android.internal.R.interpolator.fast_out_slow_in);
|
||||
|
||||
int taskBarDismissDozeDelaySeconds = getResources().getInteger(
|
||||
R.integer.recents_task_bar_dismiss_delay_seconds);
|
||||
@@ -390,7 +417,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
|
||||
// Pick up all the freeform tasks
|
||||
int firstVisStackIndex = isValidVisibleStackRange ? visibleStackRange[0] : 0;
|
||||
for (int i = mStack.getTaskCount() - 1; i > firstVisStackIndex; i--) {
|
||||
for (int i = mStack.getTaskCount() - 1; i >= firstVisStackIndex; i--) {
|
||||
Task task = tasks.get(i);
|
||||
if (!task.isFreeformTask()) {
|
||||
continue;
|
||||
@@ -411,6 +438,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
// Animate the task into place
|
||||
tv.updateViewPropertiesToTaskTransform(transform,
|
||||
mStackViewsAnimationDuration, mRequestUpdateClippingListener);
|
||||
|
||||
// Reattach it in the right z order
|
||||
detachViewFromParent(tv);
|
||||
int insertIndex = -1;
|
||||
int taskIndex = mStack.indexOfTask(task);
|
||||
taskViews = getTaskViews();
|
||||
taskViewCount = taskViews.size();
|
||||
for (int j = 0; j < taskViewCount; j++) {
|
||||
Task tvTask = taskViews.get(j).getTask();
|
||||
if (taskIndex < mStack.indexOfTask(tvTask)) {
|
||||
insertIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
attachViewToParent(tv, insertIndex, tv.getLayoutParams());
|
||||
|
||||
// Update the task views list after adding the new task view
|
||||
updateTaskViewsList();
|
||||
}
|
||||
|
||||
// Pick up all the newly visible children and update all the existing children
|
||||
@@ -514,7 +559,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
|
||||
/** Updates the min and max virtual scroll bounds */
|
||||
void updateMinMaxScroll(boolean boundScrollToNewMinMax) {
|
||||
void updateLayout(boolean boundScrollToNewMinMax) {
|
||||
// Compute the min and max scroll values
|
||||
mLayoutAlgorithm.update(mStack);
|
||||
|
||||
@@ -700,21 +745,21 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
mLayoutAlgorithm.initialize(taskStackBounds);
|
||||
|
||||
// Update the scroll bounds
|
||||
updateMinMaxScroll(false);
|
||||
updateLayout(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is ONLY used from AlternateRecentsComponent to update the dummy stack view for purposes
|
||||
* This is ONLY used from the Recents component to update the dummy stack view for purposes
|
||||
* of getting the task rect to animate to.
|
||||
*/
|
||||
public void updateMinMaxScrollForStack(TaskStack stack) {
|
||||
public void updateLayoutForStack(TaskStack stack) {
|
||||
mStack = stack;
|
||||
updateMinMaxScroll(false);
|
||||
updateLayout(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the maximum number of visible tasks and thumbnails. Requires that
|
||||
* updateMinMaxScrollForStack() is called first.
|
||||
* updateLayoutForStack() is called first.
|
||||
*/
|
||||
public TaskStackLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
|
||||
return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getTasks());
|
||||
@@ -1002,7 +1047,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
|
||||
// Update the min/max scroll and animate other task views into their new positions
|
||||
updateMinMaxScroll(true);
|
||||
updateLayout(true);
|
||||
|
||||
if (wasFrontMostTask) {
|
||||
// Since the max scroll progress is offset from the bottom of the stack, just scroll
|
||||
@@ -1028,7 +1073,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
|
||||
// Update the min/max scroll and animate other task views into their new positions
|
||||
updateMinMaxScroll(true);
|
||||
updateLayout(true);
|
||||
|
||||
// Animate all the tasks into place
|
||||
requestSynchronizeStackViewsWithModel(200);
|
||||
@@ -1088,7 +1133,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
mLayoutAlgorithm.updateTaskOffsets(mStack.getTasks());
|
||||
|
||||
// Scroll the item to the top of the stack (sans-peek) rect so that we can see it better
|
||||
updateMinMaxScroll(false);
|
||||
updateLayout(false);
|
||||
float overlapHeight = mLayoutAlgorithm.getTaskOverlapHeight();
|
||||
setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight));
|
||||
boundScrollRaw();
|
||||
@@ -1117,7 +1162,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
mLayoutAlgorithm.updateTaskOffsets(mStack.getTasks());
|
||||
|
||||
// Restore the stashed scroll
|
||||
updateMinMaxScroll(false);
|
||||
updateLayout(false);
|
||||
setStackScrollRaw(mStashedScroll);
|
||||
boundScrollRaw();
|
||||
|
||||
@@ -1305,6 +1350,79 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragStartEvent event) {
|
||||
if (event.task.isFreeformTask()) {
|
||||
// Animate to the front of the stack
|
||||
mStackScroller.animateScroll(mStackScroller.getStackScroll(),
|
||||
mLayoutAlgorithm.mInitialScrollP, null);
|
||||
}
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragStartInitializeDropTargetsEvent event) {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
if (ssp.hasFreeformWorkspaceSupport()) {
|
||||
event.handler.registerDropTargetForCurrentDrag(mStackDropTarget);
|
||||
event.handler.registerDropTargetForCurrentDrag(mFreeformWorkspaceDropTarget);
|
||||
}
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragDropTargetChangedEvent event) {
|
||||
// TODO: Animate the freeform workspace background etc.
|
||||
}
|
||||
|
||||
public final void onBusEvent(final DragEndEvent event) {
|
||||
if (event.dropTarget != mFreeformWorkspaceDropTarget &&
|
||||
event.dropTarget != mStackDropTarget) {
|
||||
return;
|
||||
}
|
||||
if (event.task.isFreeformTask() && event.dropTarget == mFreeformWorkspaceDropTarget) {
|
||||
// TODO: Animate back into view
|
||||
return;
|
||||
}
|
||||
if (!event.task.isFreeformTask() && event.dropTarget == mStackDropTarget) {
|
||||
// TODO: Animate back into view
|
||||
return;
|
||||
}
|
||||
|
||||
// Move the task to the right position in the stack (ie. the front of the stack if freeform
|
||||
// or the front of the stack if fullscreen). Note, we MUST move the tasks before we update
|
||||
// their stack ids, otherwise, the keys will have changed.
|
||||
if (event.dropTarget == mFreeformWorkspaceDropTarget) {
|
||||
mStack.moveTaskToStack(event.task, FREEFORM_WORKSPACE_STACK_ID);
|
||||
updateLayout(true);
|
||||
} else if (event.dropTarget == mStackDropTarget) {
|
||||
mStack.moveTaskToStack(event.task, FULLSCREEN_WORKSPACE_STACK_ID);
|
||||
updateLayout(true);
|
||||
}
|
||||
|
||||
event.postAnimationTrigger.increment();
|
||||
event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
ssp.moveTaskToStack(event.task.key.id, event.task.key.stackId);
|
||||
}
|
||||
});
|
||||
|
||||
// Animate the drag view to the new position
|
||||
mLayoutAlgorithm.getStackTransform(event.task, mStackScroller.getStackScroll(),
|
||||
mTmpTransform, null);
|
||||
event.dragView.animate()
|
||||
.scaleX(mTmpTransform.scale)
|
||||
.scaleY(mTmpTransform.scale)
|
||||
.translationX((mLayoutAlgorithm.mTaskRect.left - event.dragView.getLeft())
|
||||
+ mTmpTransform.translationX)
|
||||
.translationY((mLayoutAlgorithm.mTaskRect.top - event.dragView.getTop())
|
||||
+ mTmpTransform.translationY)
|
||||
.setDuration(175)
|
||||
.setInterpolator(mFastOutSlowInInterpolator)
|
||||
.withEndAction(event.postAnimationTrigger.decrementAsRunnable())
|
||||
.start();
|
||||
|
||||
// Animate the other views into place
|
||||
requestSynchronizeStackViewsWithModel(175);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the task from the stack, and updates the focus to the next task in the stack if the
|
||||
* removed TaskView was focused.
|
||||
|
||||
@@ -51,6 +51,7 @@ import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskStack;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
|
||||
/* A task view */
|
||||
@@ -708,6 +709,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
@Override
|
||||
public void onTaskDataLoaded() {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
RecentsConfiguration config = Recents.getConfiguration();
|
||||
if (mThumbnailView != null && mHeaderView != null) {
|
||||
// Bind each of the views to the new task data
|
||||
@@ -715,7 +717,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
mHeaderView.rebindToTask(mTask);
|
||||
// Rebind any listeners
|
||||
mActionButtonView.setOnClickListener(this);
|
||||
setOnLongClickListener(config.hasDockedTasks ? null : this);
|
||||
|
||||
// Only enable long-click if we have a freeform workspace to drag to/from, or if we
|
||||
// aren't already docked
|
||||
if (ssp.hasFreeformWorkspaceSupport() || !config.hasDockedTasks) {
|
||||
setOnLongClickListener(this);
|
||||
} else {
|
||||
setOnLongClickListener(null);
|
||||
}
|
||||
}
|
||||
mTaskDataLoaded = true;
|
||||
}
|
||||
@@ -759,15 +768,21 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
// Start listening for drag events
|
||||
setClipViewInStack(false);
|
||||
|
||||
final int width = (int) (getScaleX() * getWidth());
|
||||
final int height = (int) (getScaleY() * getHeight());
|
||||
final float finalScale = getScaleX() * 1.05f;
|
||||
final int width = getWidth();
|
||||
final int height = getHeight();
|
||||
Bitmap dragBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(dragBitmap);
|
||||
c.scale(getScaleX(), getScaleY());
|
||||
mThumbnailView.draw(c);
|
||||
mHeaderView.draw(c);
|
||||
c.setBitmap(null);
|
||||
|
||||
// The downTouchPos is relative to the currently transformed TaskView, but we will be
|
||||
// dragging a copy of the full task view, which makes it easier for us to animate them
|
||||
// when the user drops
|
||||
mDownTouchPos.x += ((1f - getScaleX()) * width) / 2;
|
||||
mDownTouchPos.y += ((1f - getScaleY()) * height) / 2;
|
||||
|
||||
// Initiate the drag
|
||||
final DragView dragView = new DragView(getContext(), dragBitmap, mDownTouchPos);
|
||||
dragView.setOutlineProvider(new ViewOutlineProvider() {
|
||||
@@ -776,6 +791,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
outline.setRect(0, 0, width, height);
|
||||
}
|
||||
});
|
||||
dragView.setScaleX(getScaleX());
|
||||
dragView.setScaleY(getScaleY());
|
||||
dragView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
@@ -785,8 +802,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
dragView.setElevation(getElevation());
|
||||
dragView.setTranslationZ(getTranslationZ());
|
||||
dragView.animate()
|
||||
.scaleX(1.05f)
|
||||
.scaleY(1.05f)
|
||||
.scaleX(finalScale)
|
||||
.scaleY(finalScale)
|
||||
.setDuration(175)
|
||||
.setInterpolator(mFastOutSlowInInterpolator)
|
||||
.start();
|
||||
@@ -807,18 +824,19 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
/**** Events ****/
|
||||
|
||||
public final void onBusEvent(DragEndEvent event) {
|
||||
event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// If docked state == null:
|
||||
// Animate the drag view back from where it is, to the view location, then after it returns,
|
||||
// update the clip state
|
||||
setClipViewInStack(true);
|
||||
if (!(event.dropTarget instanceof TaskStack.DockState)) {
|
||||
event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Show this task view
|
||||
setVisibility(View.VISIBLE);
|
||||
|
||||
// Show this task view
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
// Animate the drag view back from where it is, to the view location, then after
|
||||
// it returns, update the clip state
|
||||
setClipViewInStack(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user