Initial changes to drag and drop to docked task.
Change-Id: I5e7a435a4061d902e5de0a54cc386388bc2b565e
This commit is contained in:
@@ -26,6 +26,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
@@ -41,6 +42,8 @@ import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEven
|
||||
import com.android.systemui.recents.events.ui.DismissTaskEvent;
|
||||
import com.android.systemui.recents.events.ui.ResizeTaskEvent;
|
||||
import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
|
||||
import com.android.systemui.recents.misc.Console;
|
||||
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
@@ -612,6 +615,18 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
getResizeTaskDebugDialog().showResizeTaskDialog(event.task, mRecentsView);
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragStartEvent event) {
|
||||
// Lock the orientation while dragging
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
|
||||
|
||||
// TODO: docking requires custom accessibility actions
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragEndEvent event) {
|
||||
// Unlock the orientation when dragging completes
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_BEHIND);
|
||||
}
|
||||
|
||||
private void refreshSearchWidgetView() {
|
||||
if (mSearchWidgetInfo != null) {
|
||||
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.graphics.Rect;
|
||||
import android.provider.Settings;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.recents.model.RecentsTaskLoader;
|
||||
|
||||
/**
|
||||
* Application resources that can be retrieved from the application context and are not specifically
|
||||
@@ -70,6 +71,7 @@ public class RecentsConfiguration {
|
||||
public final int smallestWidth;
|
||||
|
||||
/** Misc **/
|
||||
public boolean hasDockedTasks;
|
||||
public boolean useHardwareLayers;
|
||||
public boolean fakeShadows;
|
||||
public int svelteLevel;
|
||||
@@ -114,6 +116,7 @@ public class RecentsConfiguration {
|
||||
lockToAppEnabled = ssp.getSystemSetting(context,
|
||||
Settings.System.LOCK_TO_APP_ENABLED) != 0;
|
||||
multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
|
||||
hasDockedTasks = ssp.hasDockedTask();
|
||||
|
||||
// Recompute some values based on the given state, since we can not rely on the resource
|
||||
// system to get certain values.
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.model.TaskStack;
|
||||
|
||||
/**
|
||||
* This event is sent when a user drag enters or exits a dock region.
|
||||
*/
|
||||
public class DragDockStateChangedEvent extends EventBus.Event {
|
||||
|
||||
public final Task task;
|
||||
public final TaskStack.DockState dockState;
|
||||
|
||||
public DragDockStateChangedEvent(Task task, TaskStack.DockState dockState) {
|
||||
this.task = task;
|
||||
this.dockState = dockState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.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.TaskView;
|
||||
|
||||
/**
|
||||
* This event is sent whenever a drag ends.
|
||||
*/
|
||||
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 ReferenceCountedTrigger postAnimationTrigger;
|
||||
|
||||
public DragEndEvent(Task task, TaskView taskView, DragView dragView,
|
||||
TaskStack.DockState dockState, ReferenceCountedTrigger postAnimationTrigger) {
|
||||
this.task = task;
|
||||
this.taskView = taskView;
|
||||
this.dragView = dragView;
|
||||
this.dockState = dockState;
|
||||
this.postAnimationTrigger = postAnimationTrigger;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.DragView;
|
||||
import com.android.systemui.recents.views.TaskView;
|
||||
|
||||
/**
|
||||
* This event is sent whenever a drag starts.
|
||||
*/
|
||||
public class DragStartEvent extends EventBus.Event {
|
||||
|
||||
public final Task task;
|
||||
public final TaskView taskView;
|
||||
public final DragView dragView;
|
||||
|
||||
public DragStartEvent(Task task, TaskView taskView, DragView dragView) {
|
||||
this.task = task;
|
||||
this.taskView = taskView;
|
||||
this.dragView = dragView;
|
||||
}
|
||||
}
|
||||
@@ -327,6 +327,21 @@ public class SystemServicesProxy {
|
||||
return mAm.isInHomeStack(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether there are any docked tasks.
|
||||
*/
|
||||
public boolean hasDockedTask() {
|
||||
if (mIam == null) return false;
|
||||
|
||||
ActivityManager.StackInfo stackInfo = null;
|
||||
try {
|
||||
stackInfo = mIam.getStackInfo(ActivityManager.DOCKED_STACK_ID);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return stackInfo != null;
|
||||
}
|
||||
|
||||
/** Returns the top task thumbnail for the given task id */
|
||||
public Bitmap getTaskThumbnail(int taskId) {
|
||||
if (mAm == null) return null;
|
||||
|
||||
@@ -21,12 +21,29 @@ import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/* Common code */
|
||||
public class Utilities {
|
||||
|
||||
/**
|
||||
* @return the first parent walking up the view hierarchy that has the given class type.
|
||||
*
|
||||
* @param parentClass must be a class derived from {@link View}
|
||||
*/
|
||||
public static <T extends View> T findParent(View v, Class<T> parentClass) {
|
||||
ViewParent parent = v.getParent();
|
||||
while (parent != null) {
|
||||
if (parent.getClass().equals(parentClass)) {
|
||||
return (T) parent;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Scales a rect about its centroid */
|
||||
public static void scaleRectAboutCenter(Rect r, float scale) {
|
||||
if (scale != 1.0f) {
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package com.android.systemui.recents.model;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.Constants;
|
||||
import com.android.systemui.recents.misc.NamedCounter;
|
||||
@@ -30,6 +33,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* An interface for a task filter to query whether a particular task should show in a stack.
|
||||
@@ -174,6 +180,63 @@ public class TaskStack {
|
||||
public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
|
||||
}
|
||||
|
||||
|
||||
public enum DockState {
|
||||
LEFT(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
|
||||
new RectF(0, 0, 0.25f, 1), new RectF(0, 0, 0.5f, 1), new RectF(0.5f, 0, 1, 1)),
|
||||
TOP(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
|
||||
new RectF(0, 0, 1, 0.25f), new RectF(0, 0, 1, 0.5f), new RectF(0, 0.5f, 1, 1)),
|
||||
RIGHT(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
|
||||
new RectF(0.75f, 0, 1, 1), new RectF(0.5f, 0, 1, 1), new RectF(0, 0, 0.5f, 1)),
|
||||
BOTTOM(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
|
||||
new RectF(0, 0.75f, 1, 1), new RectF(0, 0.5f, 1, 1), new RectF(0, 0, 1, 0.5f));
|
||||
|
||||
public final int createMode;
|
||||
private final RectF touchArea;
|
||||
private final RectF dockArea;
|
||||
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
|
||||
*/
|
||||
DockState(int createMode, RectF touchArea, RectF dockArea, RectF stackArea) {
|
||||
this.createMode = createMode;
|
||||
this.touchArea = touchArea;
|
||||
this.dockArea = dockArea;
|
||||
this.stackArea = stackArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether {@param x} and {@param y} are contained in the touch area scaled to the
|
||||
* given {@param width} and {@param height}.
|
||||
*/
|
||||
public boolean touchAreaContainsPoint(int width, int height, float x, float y) {
|
||||
int left = (int) (touchArea.left * width);
|
||||
int top = (int) (touchArea.top * height);
|
||||
int right = (int) (touchArea.right * width);
|
||||
int bottom = (int) (touchArea.bottom * height);
|
||||
return x >= left && y >= top && x <= right && y <= bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the docked task bounds with the given {@param width} and {@param height}.
|
||||
*/
|
||||
public Rect getDockedBounds(int width, int height) {
|
||||
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(int width, int height) {
|
||||
return new Rect((int) (stackArea.left * width), (int) (stackArea.top * height),
|
||||
(int) (stackArea.right * width), (int) (stackArea.bottom * height));
|
||||
}
|
||||
}
|
||||
|
||||
// The task offset to apply to a task id as a group affiliation
|
||||
static final int IndividualTaskIdOffset = 1 << 16;
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.widget.ImageView;
|
||||
|
||||
public class DragView extends ImageView {
|
||||
|
||||
// The offset from the top-left of the dragBitmap
|
||||
Point mTopLeftOffset;
|
||||
|
||||
public DragView(Context context, Bitmap dragBitmap, Point tlOffset) {
|
||||
super(context);
|
||||
|
||||
mTopLeftOffset = tlOffset;
|
||||
setImageBitmap(dragBitmap);
|
||||
}
|
||||
|
||||
public Point getTopLeftOffset() {
|
||||
return mTopLeftOffset;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.IRemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
@@ -30,19 +31,25 @@ import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.AppTransitionAnimationSpec;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.Constants;
|
||||
import com.android.systemui.recents.RecentsActivity;
|
||||
import com.android.systemui.recents.RecentsAppWidgetHostView;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.events.ui.DismissTaskEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent;
|
||||
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;
|
||||
import com.android.systemui.recents.model.RecentsTaskLoader;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
@@ -78,6 +85,11 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
TaskStackView mTaskStackView;
|
||||
RecentsAppWidgetHostView mSearchBar;
|
||||
RecentsViewCallbacks mCb;
|
||||
|
||||
RecentsViewTouchHandler mTouchHandler;
|
||||
DragView mDragView;
|
||||
ColorDrawable mDockRegionOverlay;
|
||||
|
||||
Interpolator mFastOutSlowInInterpolator;
|
||||
|
||||
Rect mSystemInsets = new Rect();
|
||||
@@ -96,10 +108,14 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
|
||||
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setWillNotDraw(false);
|
||||
mConfig = RecentsConfiguration.getInstance();
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
|
||||
com.android.internal.R.interpolator.fast_out_slow_in);
|
||||
mTouchHandler = new RecentsViewTouchHandler(this);
|
||||
mDockRegionOverlay = new ColorDrawable(0x66000000);
|
||||
mDockRegionOverlay.setAlpha(0);
|
||||
}
|
||||
|
||||
/** Sets the callbacks */
|
||||
@@ -200,6 +216,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
ArrayList<Task> tasks = stack.getTasks();
|
||||
|
||||
// Find the launch task in the stack
|
||||
// TODO: replace this with an event from RecentsActivity
|
||||
if (!tasks.isEmpty()) {
|
||||
int taskCount = tasks.size();
|
||||
for (int j = 0; j < taskCount; j++) {
|
||||
@@ -267,6 +284,20 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
|
||||
EventBus.getDefault().register(mTouchHandler, RecentsActivity.EVENT_BUS_PRIORITY + 1);
|
||||
super.onAttachedToWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
EventBus.getDefault().unregister(this);
|
||||
EventBus.getDefault().unregister(mTouchHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called with the full size of the window since we are handling our own insets.
|
||||
*/
|
||||
@@ -293,6 +324,12 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
if (mDragView != null) {
|
||||
mDragView.measure(
|
||||
MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
|
||||
}
|
||||
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
@@ -314,6 +351,11 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
|
||||
mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
|
||||
}
|
||||
|
||||
if (mDragView != null) {
|
||||
mDragView.layout(left, top, left + mDragView.getMeasuredWidth(),
|
||||
top + mDragView.getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -323,6 +365,24 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
return insets.consumeSystemWindowInsets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return mTouchHandler.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return mTouchHandler.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
super.dispatchDraw(canvas);
|
||||
if (mDockRegionOverlay.getAlpha() > 0) {
|
||||
mDockRegionOverlay.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
/** Notifies each task view of the user interaction. */
|
||||
public void onUserInteraction() {
|
||||
// Get the first stack view
|
||||
@@ -697,4 +757,64 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**** EventBus Events ****/
|
||||
|
||||
public final void onBusEvent(DragStartEvent event) {
|
||||
// Add the drag view
|
||||
mDragView = event.dragView;
|
||||
addView(mDragView);
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragDockStateChangedEvent event) {
|
||||
// Update the task stack positions, and then
|
||||
if (event.dockState != null) {
|
||||
// Draw an overlay on the bounds of the dock task
|
||||
mDockRegionOverlay.setBounds(
|
||||
event.dockState.getDockedBounds(getMeasuredWidth(), getMeasuredHeight()));
|
||||
mDockRegionOverlay.setAlpha(255);
|
||||
} else {
|
||||
mDockRegionOverlay.setAlpha(0);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public final void onBusEvent(final DragEndEvent event) {
|
||||
event.postAnimationTrigger.increment();
|
||||
event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Remove the drag view
|
||||
removeView(mDragView);
|
||||
mDragView = null;
|
||||
mDockRegionOverlay.setAlpha(0);
|
||||
invalidate();
|
||||
|
||||
// Dock the new task if we are hovering over a valid dock state
|
||||
if (event.dockState != null) {
|
||||
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
|
||||
ssp.setTaskResizeable(event.task.key.id);
|
||||
ssp.dockTask(event.task.key.id, event.dockState.createMode);
|
||||
launchTask(event.task, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (event.dockState == null) {
|
||||
// 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;
|
||||
event.dragView.animate()
|
||||
.alpha(1f)
|
||||
.translationX(left + event.taskView.getTranslationX())
|
||||
.translationY(top + event.taskView.getTranslationY())
|
||||
.setDuration(175)
|
||||
.setInterpolator(new AccelerateInterpolator(1.5f))
|
||||
.withEndAction(event.postAnimationTrigger.decrementAsRunnable())
|
||||
.withLayer()
|
||||
.start();
|
||||
} else {
|
||||
event.postAnimationTrigger.decrement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.view.MotionEvent;
|
||||
import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
|
||||
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
|
||||
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskStack;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the dock regions for each orientation.
|
||||
*/
|
||||
class DockRegion {
|
||||
public static TaskStack.DockState[] LANDSCAPE = {
|
||||
TaskStack.DockState.LEFT, TaskStack.DockState.RIGHT
|
||||
};
|
||||
public static TaskStack.DockState[] PORTRAIT = {
|
||||
TaskStack.DockState.TOP, TaskStack.DockState.BOTTOM
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles touch events for a RecentsView.
|
||||
*/
|
||||
class RecentsViewTouchHandler {
|
||||
|
||||
private RecentsView mRv;
|
||||
|
||||
private Task mDragTask;
|
||||
private TaskView mTaskView;
|
||||
private DragView mDragView;
|
||||
|
||||
private Point mDownPos = new Point();
|
||||
private boolean mDragging;
|
||||
private TaskStack.DockState mLastDockState;
|
||||
|
||||
public RecentsViewTouchHandler(RecentsView rv) {
|
||||
mRv = rv;
|
||||
}
|
||||
|
||||
/** Touch preprocessing for handling below */
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
int action = ev.getAction();
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mDownPos.set((int) ev.getX(), (int) ev.getY());
|
||||
break;
|
||||
}
|
||||
return mDragging;
|
||||
}
|
||||
|
||||
/** Handles touch events once we have intercepted them */
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (!mDragging) return false;
|
||||
|
||||
boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
|
||||
Configuration.ORIENTATION_LANDSCAPE;
|
||||
int action = ev.getAction();
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mDownPos.set((int) ev.getX(), (int) ev.getY());
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
int width = mRv.getMeasuredWidth();
|
||||
int height = mRv.getMeasuredHeight();
|
||||
float evX = ev.getX();
|
||||
float evY = ev.getY();
|
||||
float x = evX - mDragView.getTopLeftOffset().x;
|
||||
float y = evY - mDragView.getTopLeftOffset().y;
|
||||
|
||||
// Update the dock state
|
||||
TaskStack.DockState[] dockStates = isLandscape ?
|
||||
DockRegion.LANDSCAPE : DockRegion.PORTRAIT;
|
||||
TaskStack.DockState foundDockState = null;
|
||||
for (int i = 0; i < dockStates.length; i++) {
|
||||
TaskStack.DockState state = dockStates[i];
|
||||
if (state.touchAreaContainsPoint(width, height, evX, evY)) {
|
||||
foundDockState = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mLastDockState != foundDockState) {
|
||||
mLastDockState = foundDockState;
|
||||
EventBus.getDefault().send(new DragDockStateChangedEvent(mDragTask,
|
||||
foundDockState));
|
||||
}
|
||||
|
||||
mDragView.setTranslationX(x);
|
||||
mDragView.setTranslationY(y);
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL: {
|
||||
ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(
|
||||
mRv.getContext(), null, null, null);
|
||||
postAnimationTrigger.increment();
|
||||
EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, mDragView,
|
||||
mLastDockState, postAnimationTrigger));
|
||||
postAnimationTrigger.decrement();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**** Events ****/
|
||||
|
||||
public final void onBusEvent(DragStartEvent event) {
|
||||
mRv.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
mDragging = true;
|
||||
mDragTask = event.task;
|
||||
mTaskView = event.taskView;
|
||||
mDragView = event.dragView;
|
||||
|
||||
float x = mDownPos.x - mDragView.getTopLeftOffset().x;
|
||||
float y = mDownPos.y - mDragView.getTopLeftOffset().y;
|
||||
mDragView.setTranslationX(x);
|
||||
mDragView.setTranslationY(y);
|
||||
}
|
||||
|
||||
public final void onBusEvent(DragEndEvent event) {
|
||||
mDragging = false;
|
||||
mDragTask = null;
|
||||
mTaskView = null;
|
||||
mDragView = null;
|
||||
mLastDockState = null;
|
||||
}
|
||||
}
|
||||
@@ -1296,7 +1296,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
RecentsTaskLoader.getInstance().loadTaskData(task);
|
||||
|
||||
// If the doze trigger has already fired, then update the state for this task view
|
||||
if (mUIDozeTrigger.hasTriggered()) {
|
||||
if (mUIDozeTrigger.hasTriggered() || mConfig.multiWindowEnabled) {
|
||||
tv.setNoUserInteractionState();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,13 +21,17 @@ import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
@@ -36,17 +40,22 @@ import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.Constants;
|
||||
import com.android.systemui.recents.RecentsActivity;
|
||||
import com.android.systemui.recents.RecentsActivityLaunchState;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.events.ui.DismissTaskEvent;
|
||||
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;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.RecentsTaskLoader;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
|
||||
/* A task view */
|
||||
public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
View.OnClickListener {
|
||||
View.OnClickListener, View.OnLongClickListener {
|
||||
|
||||
/** The TaskView callbacks */
|
||||
interface TaskViewCallbacks {
|
||||
@@ -79,6 +88,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
View mActionButtonView;
|
||||
TaskViewCallbacks mCb;
|
||||
|
||||
Point mDownTouchPos = new Point();
|
||||
|
||||
Interpolator mFastOutSlowInInterpolator;
|
||||
Interpolator mFastOutLinearInInterpolator;
|
||||
Interpolator mQuintOutInterpolator;
|
||||
@@ -168,6 +179,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mDownTouchPos.set((int) (ev.getX() * getScaleX()), (int) (ev.getY() * getScaleY()));
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
@@ -719,6 +738,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
mHeaderView.rebindToTask(mTask);
|
||||
// Rebind any listeners
|
||||
mActionButtonView.setOnClickListener(this);
|
||||
setOnLongClickListener(mConfig.hasDockedTasks ? null : this);
|
||||
}
|
||||
mTaskDataLoaded = true;
|
||||
}
|
||||
@@ -753,4 +773,69 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
mCb.onTaskViewClicked(this, mTask, (v == mActionButtonView));
|
||||
}
|
||||
}
|
||||
|
||||
/**** View.OnLongClickListener Implementation ****/
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (v == this) {
|
||||
// Start listening for drag events
|
||||
setClipViewInStack(false);
|
||||
|
||||
int width = (int) (getScaleX() * getWidth());
|
||||
int height = (int) (getScaleY() * 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);
|
||||
|
||||
// Initiate the drag
|
||||
final DragView dragView = new DragView(getContext(), dragBitmap, mDownTouchPos);
|
||||
dragView.setOutlineProvider(mViewBounds);
|
||||
dragView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
// Hide this task view after the drag view is attached
|
||||
setVisibility(View.INVISIBLE);
|
||||
// Animate the alpha slightly to indicate dragging
|
||||
dragView.setElevation(getElevation());
|
||||
dragView.setTranslationZ(getTranslationZ());
|
||||
dragView.animate()
|
||||
.alpha(0.75f)
|
||||
.setDuration(175)
|
||||
.setInterpolator(new AccelerateInterpolator(1.5f))
|
||||
.withLayer()
|
||||
.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
}
|
||||
});
|
||||
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
|
||||
EventBus.getDefault().send(new DragStartEvent(mTask, this, dragView));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**** 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);
|
||||
|
||||
// Show this task view
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ public class TaskViewHeader extends FrameLayout
|
||||
// In accessibility, a single click on the focused app info button will show it
|
||||
EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
|
||||
} else if (v == mDismissButton) {
|
||||
TaskView tv = (TaskView) getParent().getParent();
|
||||
TaskView tv = Utilities.findParent(this, TaskView.class);
|
||||
tv.dismissTask();
|
||||
|
||||
// Keep track of deletions by the dismiss button
|
||||
|
||||
Reference in New Issue
Block a user