}
System.out.println("Performing idle maintenance...");
- Intent intent = new Intent(
- "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE");
- mAm.broadcastIntent(null, intent, null, null, 0, null, null, null,
- android.app.AppOpsManager.OP_NONE, null, true, false, UserHandle.USER_ALL);
+ try {
+ mAm.sendIdleJobTrigger();
+ } catch (RemoteException e) {
+ }
}
private void runScreenCompat() throws Exception {
boolean performGlobalAction(int action);
- oneway void disableSelf();
+ void disableSelf();
oneway void setOnKeyEventResult(boolean handled, int sequence);
case SET_LOCK_SCREEN_SHOWN_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- setLockScreenShown(data.readInt() != 0);
+ final boolean showing = data.readInt() != 0;
+ final boolean occluded = data.readInt() != 0;
+ setLockScreenShown(showing, occluded);
reply.writeNoException();
return true;
}
reply.writeNoException();
return true;
}
+ case SEND_IDLE_JOB_TRIGGER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ sendIdleJobTrigger();
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
reply.recycle();
return pfd;
}
- public void setLockScreenShown(boolean shown) throws RemoteException
+ public void setLockScreenShown(boolean showing, boolean occluded) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeInt(shown ? 1 : 0);
+ data.writeInt(showing ? 1 : 0);
+ data.writeInt(occluded ? 1 : 0);
mRemote.transact(SET_LOCK_SCREEN_SHOWN_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
+ public void sendIdleJobTrigger() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(SEND_IDLE_JOB_TRIGGER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
IActivityContainerCallback callback) throws RemoteException {
Parcel data = Parcel.obtain();
public void forceStopPackage(final String packageName, int userId) throws RemoteException;
// Note: probably don't want to allow applications access to these.
- public void setLockScreenShown(boolean shown) throws RemoteException;
+ public void setLockScreenShown(boolean showing, boolean occluded) throws RemoteException;
public void unhandledBack() throws RemoteException;
public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException;
public void performIdleMaintenance() throws RemoteException;
+ public void sendIdleJobTrigger() throws RemoteException;
+
public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
IActivityContainerCallback callback) throws RemoteException;
int SWAP_DOCKED_AND_FULLSCREEN_STACK = IBinder.FIRST_CALL_TRANSACTION + 372;
int NOTIFY_LOCKED_PROFILE = IBinder.FIRST_CALL_TRANSACTION + 373;
int START_CONFIRM_DEVICE_CREDENTIAL_INTENT = IBinder.FIRST_CALL_TRANSACTION + 374;
+ int SEND_IDLE_JOB_TRIGGER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 375;
}
@Override
public int hashCode() {
- return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId, mManufacturerData,
- mManufacturerDataMask, mServiceDataUuid, mServiceData, mServiceDataMask,
- mServiceUuid, mServiceUuidMask);
+ return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId,
+ Arrays.hashCode(mManufacturerData),
+ Arrays.hashCode(mManufacturerDataMask),
+ mServiceDataUuid,
+ Arrays.hashCode(mServiceData),
+ Arrays.hashCode(mServiceDataMask),
+ mServiceUuid, mServiceUuidMask);
}
@Override
ScanFilter other = (ScanFilter) obj;
return Objects.equals(mDeviceName, other.mDeviceName) &&
Objects.equals(mDeviceAddress, other.mDeviceAddress) &&
- mManufacturerId == other.mManufacturerId &&
+ mManufacturerId == other.mManufacturerId &&
Objects.deepEquals(mManufacturerData, other.mManufacturerData) &&
Objects.deepEquals(mManufacturerDataMask, other.mManufacturerDataMask) &&
- Objects.deepEquals(mServiceDataUuid, other.mServiceDataUuid) &&
+ Objects.equals(mServiceDataUuid, other.mServiceDataUuid) &&
Objects.deepEquals(mServiceData, other.mServiceData) &&
Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) &&
Objects.equals(mServiceUuid, other.mServiceUuid) &&
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
if (ris == null || ris.isEmpty()) {
// No application capable of enrolling for voice keyphrases is present.
mParseError = "No enrollment applications found";
- mKeyphrasePackageMap = null;
+ mKeyphrasePackageMap = Collections.<KeyphraseMetadata, String>emptyMap();
mKeyphrases = null;
return;
}
* and locale, null otherwise.
*/
public KeyphraseMetadata getKeyphraseMetadata(String keyphrase, Locale locale) {
- if (mKeyphrases == null || mKeyphrases.length == 0) {
- Slog.w(TAG, "Enrollment application doesn't support keyphrases");
- return null;
- }
- for (KeyphraseMetadata keyphraseMetadata : mKeyphrases) {
- // Check if the given keyphrase is supported in the locale provided by
- // the enrollment application.
- if (keyphraseMetadata.supportsPhrase(keyphrase)
- && keyphraseMetadata.supportsLocale(locale)) {
- return keyphraseMetadata;
- }
+ if (mKeyphrases != null && mKeyphrases.length > 0) {
+ for (KeyphraseMetadata keyphraseMetadata : mKeyphrases) {
+ // Check if the given keyphrase is supported in the locale provided by
+ // the enrollment application.
+ if (keyphraseMetadata.supportsPhrase(keyphrase)
+ && keyphraseMetadata.supportsLocale(locale)) {
+ return keyphraseMetadata;
+ }
+ }
}
Slog.w(TAG, "No Enrollment application supports the given keyphrase/locale");
return null;
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
- <protected-broadcast android:name="com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE" />
+ <protected-broadcast android:name="com.android.server.ACTION_TRIGGER_IDLE" />
<protected-broadcast android:name="android.intent.action.HDMI_PLUGGED" />
android:gravity="top"
systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
- <com.android.systemui.statusbar.AlphaOptimizedButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/alarm_status_collapsed"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:drawablePadding="6dp"
- android:drawableStart="@drawable/ic_access_alarms_small"
- android:textColor="#64ffffff"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_access_alarms_small"
android:paddingStart="6dp"
- android:gravity="top"
- android:background="?android:attr/selectableItemBackground"
+ android:gravity="center"
android:visibility="gone" />
</LinearLayout>
private void updateActivityLockScreenState() {
try {
- ActivityManagerNative.getDefault().setLockScreenShown(mShowing && !mOccluded);
+ ActivityManagerNative.getDefault().setLockScreenShown(mShowing, mOccluded);
} catch (RemoteException e) {
}
}
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
+import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
import com.android.systemui.recents.events.ui.UserInteractionEvent;
-import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
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;
import java.io.PrintWriter;
/**
- * The main Recents activity that is started from AlternateRecentsComponent.
+ * The main Recents activity that is started from RecentsComponent.
*/
public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreDrawListener {
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
// When the screen turns off, dismiss Recents to Home
dismissRecentsToHomeIfVisible(false);
+ } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
+ // For the time being, if the time changes, then invalidate the
+ // last-stack-active-time, this ensures that we will just show the last N tasks
+ // the next time that Recents loads, but prevents really old tasks from showing
+ // up if the task time is set forward.
+ Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
+ 0);
}
}
};
// Register the broadcast receiver to handle messages when the screen is turned off
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
registerReceiver(mSystemBroadcastReceiver, filter);
getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION);
mIgnoreAltTabRelease = true;
}
- public final void onBusEvent(final DragEndEvent event) {
- // Handle the case where we drop onto a dock region
- if (event.dropTarget instanceof TaskStack.DockState) {
- mScrimViews.animateScrimToCurrentNavBarState(false /* hasStackTasks */);
- }
- }
-
public final void onBusEvent(final DockedTopTaskEvent event) {
mRecentsView.getViewTreeObserver().addOnPreDrawListener(mRecentsDrawnEventListener);
mRecentsView.invalidate();
--- /dev/null
+/*
+ * Copyright (C) 2016 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;
+import com.android.systemui.recents.views.DropTarget;
+import com.android.systemui.recents.views.TaskView;
+
+/**
+ * This event is sent whenever a drag end is cancelled because of an error.
+ */
+public class DragEndCancelledEvent extends EventBus.AnimatedEvent {
+
+ public final TaskStack stack;
+ public final Task task;
+ public final TaskView taskView;
+
+ public DragEndCancelledEvent(TaskStack stack, Task task, TaskView taskView) {
+ this.stack = stack;
+ this.task = task;
+ this.taskView = taskView;
+ }
+}
}
/** Docks a task to the side of the screen and starts it. */
- public void startTaskInDockedMode(int taskId, int createMode) {
- if (mIam == null) return;
+ public boolean startTaskInDockedMode(int taskId, int createMode) {
+ if (mIam == null) return false;
try {
- // TODO: Determine what animation we want for the incoming task
final ActivityOptions options = ActivityOptions.makeBasic();
options.setDockCreateMode(createMode);
options.setLaunchStackId(DOCKED_STACK_ID);
mIam.startActivityFromRecents(taskId, options.toBundle());
- } catch (RemoteException e) {
+ return true;
+ } catch (RemoteException | IllegalArgumentException e) {
e.printStackTrace();
}
+ return false;
}
/** Docks an already resumed task to the side of the screen. */
}
/**
+ * Sets the given {@link View}'s frame from its current translation.
+ */
+ public static void setViewFrameFromTranslation(View v) {
+ RectF taskViewRect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+ taskViewRect.offset(v.getTranslationX(), v.getTranslationY());
+ v.setTranslationX(0);
+ v.setTranslationY(0);
+ v.setLeftTopRightBottom((int) taskViewRect.left, (int) taskViewRect.top,
+ (int) taskViewRect.right, (int) taskViewRect.bottom);
+ }
+
+ /**
* Returns a view stub for the given view id.
*/
public static ViewStub findViewStubById(View v, int stubId) {
lastStackActiveTime = 0;
}
long newLastStackActiveTime = -1;
- long prevLastActiveTime = lastStackActiveTime;
int taskCount = mRawTasks.size();
for (int i = 0; i < taskCount; i++) {
ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
- /*
- * Affiliated tasks are returned in a specific order from ActivityManager but without a
- * lastActiveTime since it hasn't yet been started. However, we later sort the task list
- * by lastActiveTime, which rearranges the tasks. For now, we need to workaround this
- * by updating the lastActiveTime of this task to the lastActiveTime of the task it is
- * affiliated with, in the same order that we encounter it in the original list (just
- * its index in the task group for the task it is affiliated with).
- *
- * If the parent task is not available, then we will use the last active time of the
- * previous task as a base point (since the task itself may not have an active time)
- * for the entire affiliated group.
- */
- if (t.persistentId != t.affiliatedTaskId) {
- Task.TaskKey parentTask = affiliatedTasks.get(t.affiliatedTaskId);
- long parentTaskLastActiveTime = parentTask != null
- ? parentTask.lastActiveTime
- : prevLastActiveTime;
- if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
- t.lastActiveTime = parentTaskLastActiveTime +
- affiliatedTaskCounts.get(t.affiliatedTaskId, 0) + 1;
- } else {
- if (t.lastActiveTime == 0) {
- t.lastActiveTime = parentTaskLastActiveTime -
- affiliatedTaskCounts.get(t.affiliatedTaskId, 0) - 1;
- }
- }
- }
-
// Compose the task key
Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
t.userId, t.firstActiveTime, t.lastActiveTime);
// This task is only shown in the stack if it statisfies the historical time or min
// number of tasks constraints. Freeform tasks are also always shown.
boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
- boolean isStackTask = isFreeformTask || (!isHistoricalTask(t) ||
- (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS)));
+ boolean isStackTask = isFreeformTask || !isHistoricalTask(t) ||
+ (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS));
boolean isLaunchTarget = taskKey.id == runningTaskId;
+
+ // The last stack active time is the baseline for which we show visible tasks. Since
+ // the system will store all the tasks, we don't want to show the tasks prior to the
+ // last visible ones, otherwise, as you dismiss them, the previous tasks may satisfy
+ // the other stack-task constraints.
if (isStackTask && newLastStackActiveTime < 0) {
newLastStackActiveTime = t.lastActiveTime;
}
allTasks.add(task);
affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
affiliatedTasks.put(taskKey.id, taskKey);
- prevLastActiveTime = t.lastActiveTime;
}
if (newLastStackActiveTime != -1) {
Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
public TaskKey key;
/**
+ * The temporary sort index in the stack, used when ordering the stack.
+ */
+ public int temporarySortIndexInStack;
+
+ /**
* The group will be computed separately from the initialization of the task
*/
@ViewDebug.ExportedProperty(deepExport=true, prefix="group_")
final V getAndInvalidateIfModified(Task.TaskKey key) {
Task.TaskKey lastKey = mKeys.get(key.id);
if (lastKey != null) {
- if ((lastKey.stackId != key.stackId) || (lastKey.lastActiveTime < key.lastActiveTime)) {
+ if ((lastKey.stackId != key.stackId) ||
+ (lastKey.lastActiveTime != key.lastActiveTime)) {
// The task has updated (been made active since the last time it was put into the
// LRU cache) or the stack id for the task has changed, invalidate that cache item
remove(key);
}
}
- // A comparator that sorts tasks by their last active time
- private Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() {
- @Override
- public int compare(Task o1, Task o2) {
- return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime);
- }
- };
-
- // A comparator that sorts tasks by their last active time and freeform state
- private Comparator<Task> FREEFORM_LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() {
+ // A comparator that sorts tasks by their freeform state
+ private Comparator<Task> FREEFORM_COMPARATOR = new Comparator<Task>() {
@Override
public int compare(Task o1, Task o2) {
if (o1.isFreeformTask() && !o2.isFreeformTask()) {
} else if (o2.isFreeformTask() && !o1.isFreeformTask()) {
return -1;
}
- return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime);
+ return Long.compare(o1.temporarySortIndexInStack, o2.temporarySortIndexInStack);
}
};
}
// Sort all the tasks to ensure they are ordered correctly
- Collections.sort(allTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
+ for (int i = allTasks.size() - 1; i >= 0; i--) {
+ allTasks.get(i).temporarySortIndexInStack = i;
+ }
+ Collections.sort(allTasks, FREEFORM_COMPARATOR);
mStackTaskList.set(allTasks);
mRawTaskList = allTasks;
}
/**
- * Computes a set of all the active and historical tasks ordered by their last active time.
+ * Computes a set of all the active and historical tasks.
*/
public ArrayList<Task> computeAllTasksList() {
ArrayList<Task> tasks = new ArrayList<>();
tasks.addAll(mStackTaskList.getTasks());
- Collections.sort(tasks, LAST_ACTIVE_TIME_COMPARATOR);
return tasks;
}
} else {
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
}
- if(mTaskStackHorizontalGridView.getStack().getTaskCount() > 1 && !mLaunchedFromHome) {
- // If there are 2 or more tasks, and we are not launching from home
- // set the selected position to the 2nd task to allow for faster app switching
- mTaskStackHorizontalGridView.setSelectedPosition(1);
- } else {
- mTaskStackHorizontalGridView.setSelectedPosition(0);
- }
// If this is a new instance from a configuration change, then we have to manually trigger
// the enter animation state, or if recents was relaunched by AM, without going through
if(mLaunchedFromHome) {
mHomeRecentsEnterExitAnimationHolder.startEnterAnimation(mPipManager.isPipShown());
}
+ mTaskStackViewAdapter.setResetAddedCards(true);
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
public void onResume() {
super.onResume();
mPipRecentsOverlayManager.onRecentsResumed();
+ if(mTaskStackHorizontalGridView.getStack().getTaskCount() > 1 && !mLaunchedFromHome) {
+ // If there are 2 or more tasks, and we are not launching from home
+ // set the selected position to the 2nd task to allow for faster app switching
+ mTaskStackHorizontalGridView.setSelectedPosition(1);
+ } else {
+ mTaskStackHorizontalGridView.setSelectedPosition(0);
+ }
}
@Override
public void onPause() {
super.onPause();
mPipRecentsOverlayManager.onRecentsPaused();
+ mTaskStackViewAdapter.setResetAddedCards(false);
}
@Override
import android.animation.Animator.AnimatorListener;
import android.content.res.Resources;
import android.graphics.drawable.TransitionDrawable;
-import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
private TransitionDrawable mDismissDrawable;
private TextView mDismissText;
- private float mDismissUnselectedAlpha;
+ private float mDismissIconNotInDismissStateAlpha;
private long mShortDuration;
private long mLongDuration;
mDismissStartYDelta = mDismissEnterYDelta * 2;
mShortDuration = res.getInteger(R.integer.dismiss_short_duration);
mLongDuration = res.getInteger(R.integer.dismiss_long_duration);
- mDismissUnselectedAlpha = res.getFloat(R.integer.dismiss_unselected_alpha);
+ mDismissIconNotInDismissStateAlpha = res.getFloat(R.integer.dismiss_unselected_alpha);
}
public void startEnterAnimation() {
mCardDismissIcon.animate()
.setDuration(mShortDuration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .alpha(mDismissUnselectedAlpha)
+ .alpha(mDismissIconNotInDismissStateAlpha)
.withEndAction(new Runnable() {
@Override
public void run() {
mInfoField.animate().setListener(null);
mThumbnailView.setAlpha(1.0f);
mThumbnailView.setTranslationY(0);
- mCardDismissIcon.setAlpha(mDismissUnselectedAlpha);
+ mCardDismissIcon.setAlpha(0.0f);
mDismissText.setAlpha(0.0f);
}
}
private static final String TAG = "TaskStackViewAdapter";
private List<Task> mTaskList;
private TaskStackHorizontalGridView mGridView;
+ private boolean mResetAddedCards;
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TaskCardView mTaskCardView;
}
@Override
+ public void onViewAttachedToWindow(ViewHolder holder) {
+ if (mResetAddedCards) {
+ holder.mTaskCardView.reset();
+ }
+ }
+
+ @Override
public void onViewDetachedFromWindow(ViewHolder holder) {
// We only want to reset on view detach if this is the last task being dismissed.
// This is so that we do not reset when shifting to apps etc, as it is not needed.
mTaskList.add(position, task);
notifyItemInserted(position);
}
+
+ public void setResetAddedCards(boolean reset) {
+ mResetAddedCards = reset;
+ }
}
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
+import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
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;
// We translated the view but we need to animate it back from the current layout-space
// rect to its final layout-space rect
- int x = (int) event.taskView.getTranslationX();
- int y = (int) event.taskView.getTranslationY();
- Rect taskViewRect = new Rect(event.taskView.getLeft(), event.taskView.getTop(),
- event.taskView.getRight(), event.taskView.getBottom());
- taskViewRect.offset(x, y);
- event.taskView.setTranslationX(0);
- event.taskView.setTranslationY(0);
- event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
- taskViewRect.right, taskViewRect.bottom);
-
- final OnAnimationStartedListener startedListener = new OnAnimationStartedListener() {
- @Override
- public void onAnimationStarted() {
- EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
- // Remove the task and don't bother relaying out, as all the tasks will be
- // relaid out when the stack changes on the multiwindow change event
- mTaskStackView.getStack().removeTask(event.task, null,
- true /* fromDockGesture */);
- }
- };
+ Utilities.setViewFrameFromTranslation(event.taskView);
// Dock the task and launch it
SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode);
- final Rect taskRect = getTaskRect(event.taskView);
- IAppTransitionAnimationSpecsFuture future = mTransitionHelper.getAppTransitionFuture(
- new AnimationSpecComposer() {
- @Override
- public List<AppTransitionAnimationSpec> composeSpecs() {
- return mTransitionHelper.composeDockAnimationSpec(
- event.taskView, taskRect);
- }
- });
- ssp.overridePendingAppTransitionMultiThumbFuture(future,
- mTransitionHelper.wrapStartedListener(startedListener),
- true /* scaleUp */);
-
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
- event.task.getTopComponent().flattenToShortString());
+ if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) {
+ final OnAnimationStartedListener startedListener =
+ new OnAnimationStartedListener() {
+ @Override
+ public void onAnimationStarted() {
+ EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
+ // Remove the task and don't bother relaying out, as all the tasks will be
+ // relaid out when the stack changes on the multiwindow change event
+ mTaskStackView.getStack().removeTask(event.task, null,
+ true /* fromDockGesture */);
+ }
+ };
+
+ final Rect taskRect = getTaskRect(event.taskView);
+ IAppTransitionAnimationSpecsFuture future =
+ mTransitionHelper.getAppTransitionFuture(
+ new AnimationSpecComposer() {
+ @Override
+ public List<AppTransitionAnimationSpec> composeSpecs() {
+ return mTransitionHelper.composeDockAnimationSpec(
+ event.taskView, taskRect);
+ }
+ });
+ ssp.overridePendingAppTransitionMultiThumbFuture(future,
+ mTransitionHelper.wrapStartedListener(startedListener),
+ true /* scaleUp */);
+
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
+ event.task.getTopComponent().flattenToShortString());
+ } else {
+ EventBus.getDefault().send(new DragEndCancelledEvent(mStack, event.task,
+ event.taskView));
+ }
} else {
// Animate the overlay alpha back to 0
updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, -1,
}
}
+ public final void onBusEvent(final DragEndCancelledEvent event) {
+ // Animate the overlay alpha back to 0
+ updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, -1,
+ true /* animateAlpha */, false /* animateBounds */);
+ }
+
private Rect getTaskRect(TaskView taskView) {
int[] location = taskView.getLocationOnScreen();
int viewX = location[0];
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
+import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
+import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
+import com.android.systemui.recents.model.TaskStack;
/** Manages the scrims for the various system bars. */
public class SystemBarScrimViews {
animateScrimToCurrentNavBarState(event.stack.getStackTaskCount() > 0);
}
+ public final void onBusEvent(final DragEndEvent event) {
+ // Hide the nav bar scrims once we drop to a dock region
+ if (event.dropTarget instanceof TaskStack.DockState) {
+ animateScrimToCurrentNavBarState(false /* hasStackTasks */);
+ }
+ }
+
+ public final void onBusEvent(final DragEndCancelledEvent event) {
+ // Restore the scrims to the normal state
+ animateScrimToCurrentNavBarState(event.stack.getStackTaskCount() > 0);
+ }
+
/**
* Animates the scrim to match the state of the current nav bar.
*/
- public void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
+ private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
if (mHasNavBarScrim != hasNavBarScrim) {
AnimationProps animation = hasNavBarScrim
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.DragEndCancelledEvent;
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;
}
/**
- * @see #relayoutTaskViews(AnimationProps, boolean)
+ * @see #relayoutTaskViews(AnimationProps, ArrayMap<Task, AnimationProps>, boolean)
*/
public void relayoutTaskViews(AnimationProps animation) {
- relayoutTaskViews(animation, false /* ignoreTaskOverrides */);
+ relayoutTaskViews(animation, null /* animationOverrides */,
+ false /* ignoreTaskOverrides */);
}
/**
* Relayout the the visible {@link TaskView}s to their current transforms as specified by the
* {@link TaskStackLayoutAlgorithm} with the given {@param animation}. This call cancels any
* animations that are current running on those task views, and will ensure that the children
- * {@link TaskView}s will match the set of visible tasks in the stack.
+ * {@link TaskView}s will match the set of visible tasks in the stack. If a {@link Task} has
+ * an animation provided in {@param animationOverrides}, that will be used instead.
*/
- private void relayoutTaskViews(AnimationProps animation, boolean ignoreTaskOverrides) {
+ private void relayoutTaskViews(AnimationProps animation,
+ ArrayMap<Task, AnimationProps> animationOverrides,
+ boolean ignoreTaskOverrides) {
// If we had a deferred animation, cancel that
cancelDeferredTaskViewLayoutAnimation();
int taskViewCount = taskViews.size();
for (int i = 0; i < taskViewCount; i++) {
TaskView tv = taskViews.get(i);
- int taskIndex = mStack.indexOfStackTask(tv.getTask());
+ Task task = tv.getTask();
+ int taskIndex = mStack.indexOfStackTask(task);
TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
- if (mIgnoreTasks.contains(tv.getTask().key)) {
+ if (mIgnoreTasks.contains(task.key)) {
continue;
}
+ if (animationOverrides != null && animationOverrides.containsKey(task)) {
+ animation = animationOverrides.get(task);
+ }
+
updateTaskViewToTransform(tv, transform, animation);
}
}
}
}
+ /**
+ * Updates the stack layout to its stable places.
+ */
+ private void updateLayoutToStableBounds() {
+ mWindowRect.set(mStableWindowRect);
+ mStackBounds.set(mStableStackBounds);
+ mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets);
+ mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
+ TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+ updateLayoutAlgorithm(true /* boundScroll */);
+ }
+
/** Returns the scroller. */
public TaskStackViewScroller getScroller() {
return mStackScroller;
} else {
// Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging
// task view, so add it back to the ignore set after updating the layout
- mWindowRect.set(mStableWindowRect);
- mStackBounds.set(mStableStackBounds);
removeIgnoreTask(event.task);
- mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets);
- mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
- TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
- updateLayoutAlgorithm(true /* boundScroll */);
+ updateLayoutToStableBounds();
addIgnoreTask(event.task);
}
- relayoutTaskViews(animation, ignoreTaskOverrides);
+ relayoutTaskViews(animation, null /* animationOverrides */, ignoreTaskOverrides);
}
public final void onBusEvent(final DragEndEvent event) {
});
}
- // We translated the view but we need to animate it back from the current layout-space rect
- // to its final layout-space rect
- int x = (int) event.taskView.getTranslationX();
- int y = (int) event.taskView.getTranslationY();
- Rect taskViewRect = new Rect(event.taskView.getLeft(), event.taskView.getTop(),
- event.taskView.getRight(), event.taskView.getBottom());
- taskViewRect.offset(x, y);
- event.taskView.setTranslationX(0);
- event.taskView.setTranslationY(0);
- event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
- taskViewRect.right, taskViewRect.bottom);
+ // Restore the task, so that relayout will apply to it below
+ removeIgnoreTask(event.task);
- // Animate the non-drag TaskViews back into position
- mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
- mTmpTransform, null);
- event.getAnimationTrigger().increment();
- relayoutTaskViews(new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
+ // Convert the dragging task view back to its final layout-space rect
+ Utilities.setViewFrameFromTranslation(event.taskView);
+
+ // Animate all the tasks into place
+ ArrayMap<Task, AnimationProps> animationOverrides = new ArrayMap<>();
+ animationOverrides.put(event.task, new AnimationProps(SLOW_SYNC_STACK_DURATION,
+ Interpolators.FAST_OUT_SLOW_IN,
+ event.getAnimationTrigger().decrementOnAnimationEnd()));
+ relayoutTaskViews(new AnimationProps(SLOW_SYNC_STACK_DURATION,
Interpolators.FAST_OUT_SLOW_IN));
+ event.getAnimationTrigger().increment();
+ }
- // Animate the drag TaskView back into position
- updateTaskViewToTransform(event.taskView, mTmpTransform,
- new AnimationProps(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN,
- event.getAnimationTrigger().decrementOnAnimationEnd()));
+ public final void onBusEvent(final DragEndCancelledEvent event) {
+ // Restore the pre-drag task stack bounds, including the dragging task view
removeIgnoreTask(event.task);
+ updateLayoutToStableBounds();
+
+ // Convert the dragging task view back to its final layout-space rect
+ Utilities.setViewFrameFromTranslation(event.taskView);
+
+ // Animate all the tasks into place
+ ArrayMap<Task, AnimationProps> animationOverrides = new ArrayMap<>();
+ animationOverrides.put(event.task, new AnimationProps(SLOW_SYNC_STACK_DURATION,
+ Interpolators.FAST_OUT_SLOW_IN,
+ event.getAnimationTrigger().decrementOnAnimationEnd()));
+ relayoutTaskViews(new AnimationProps(SLOW_SYNC_STACK_DURATION,
+ Interpolators.FAST_OUT_SLOW_IN));
+ event.getAnimationTrigger().increment();
}
public final void onBusEvent(IterateRecentsEvent event) {
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
+import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
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;
public final void onBusEvent(DragEndEvent event) {
if (!(event.dropTarget instanceof TaskStack.DockState)) {
- event.addPostAnimationCallback(new Runnable() {
- @Override
- public void run() {
- // Animate the drag view back from where it is, to the view location, then after
- // it returns, update the clip state
- setClipViewInStack(true);
- }
+ event.addPostAnimationCallback(() -> {
+ // Reset the clip state for the drag view after the end animation completes
+ setClipViewInStack(true);
});
}
EventBus.getDefault().unregister(this);
}
+
+ public final void onBusEvent(DragEndCancelledEvent event) {
+ // Reset the clip state for the drag view after the cancel animation completes
+ event.addPostAnimationCallback(() -> {
+ setClipViewInStack(true);
+ });
+ }
}
final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
if (indexOfKey >= 0) {
mButtonDispatchers.valueAt(indexOfKey).addView(v);
+ } else if (v instanceof ViewGroup) {
+ final ViewGroup viewGroup = (ViewGroup)v;
+ final int N = viewGroup.getChildCount();
+ for (int i = 0; i < N; i++) {
+ addToDispatchers(viewGroup.getChildAt(i));
+ }
}
}
}
protected View mSettingsContainer;
private TextView mAlarmStatus;
- private TextView mAlarmStatusCollapsed;
+ private View mAlarmStatusCollapsed;
private QSPanel mQsPanel;
mSettingsContainer = findViewById(R.id.settings_button_container);
mSettingsButton.setOnClickListener(this);
- mAlarmStatusCollapsed = (TextView) findViewById(R.id.alarm_status_collapsed);
+ mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed);
mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
mAlarmStatus.setOnClickListener(this);
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
private static final String TAG_VISIBLE_BEHIND = TAG + POSTFIX_VISIBLE_BEHIND;
+ // Mock "pretend we're idle now" broadcast action to the job scheduler; declared
+ // here so that while the job scheduler can depend on AMS, the other way around
+ // need not be the case.
+ public static final String ACTION_TRIGGER_IDLE = "com.android.server.ACTION_TRIGGER_IDLE";
+
/** Control over CPU and battery monitoring */
// write battery stats every 30 minutes.
static final long BATTERY_STATS_TIME = 30 * 60 * 1000;
mWindowManager.setEventDispatching(mBooted && !mShuttingDown);
}
- public void setLockScreenShown(boolean shown) {
+ public void setLockScreenShown(boolean showing, boolean occluded) {
if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
synchronized(this) {
long ident = Binder.clearCallingIdentity();
try {
- if (DEBUG_LOCKSCREEN) logLockScreen(" shown=" + shown);
- mLockScreenShown = shown ? LOCK_SCREEN_SHOWN : LOCK_SCREEN_HIDDEN;
+ if (DEBUG_LOCKSCREEN) logLockScreen(" showing=" + showing + " occluded=" + occluded);
+ mLockScreenShown = (showing && !occluded) ? LOCK_SCREEN_SHOWN : LOCK_SCREEN_HIDDEN;
+ if (showing && occluded) {
+ // The lock screen is currently showing, but is occluded by a window that can
+ // show on top of the lock screen. In this can we want to dismiss the docked
+ // stack since it will be complicated/risky to try to put the activity on top
+ // of the lock screen in the right fullscreen configuration.
+ mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
+ mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
+ }
+
updateSleepIfNeededLocked();
} finally {
Binder.restoreCallingIdentity(ident);
}
}
+ @Override
+ public void sendIdleJobTrigger() {
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ Intent intent = new Intent(ACTION_TRIGGER_IDLE)
+ .setPackage("android")
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ broadcastIntent(null, intent, null, null, 0, null, null, null,
+ android.app.AppOpsManager.OP_NONE, null, true, false, UserHandle.USER_ALL);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private void retrieveSettings() {
final ContentResolver resolver = mContext.getContentResolver();
final boolean freeformWindowManagement =
private static final int MAX_RECENT_BITMAPS = 3;
private static final int DEFAULT_INITIAL_CAPACITY = 5;
+ // Whether or not to move all affiliated tasks to the front when one of the tasks is launched
+ private static final boolean MOVE_AFFILIATED_TASKS_TO_FRONT = false;
+
/**
* Save recent tasks information across reboots.
*/
if (task.inRecents) {
int taskIndex = indexOf(task);
if (taskIndex >= 0) {
- if (!isAffiliated) {
+ if (!isAffiliated || MOVE_AFFILIATED_TASKS_TO_FRONT) {
// Simple case: this is not an affiliated task, so we just move it to the front.
remove(taskIndex);
add(0, task);
import android.os.SystemClock;
import android.util.Slog;
+import com.android.server.am.ActivityManagerService;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateChangedListener;
public class IdleController extends StateController {
private static final String TAG = "IdleController";
- private static final String ACTION_TRIGGER_IDLE =
- "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
-
// Policy: we decide that we're "idle" if the device has been unused /
// screen off or dreaming for at least this long
private long mInactivityIdleThreshold;
public IdlenessTracker() {
mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(ACTION_TRIGGER_IDLE)
+ Intent intent = new Intent(ActivityManagerService.ACTION_TRIGGER_IDLE)
.setPackage("android")
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
// Debugging/instrumentation
- filter.addAction(ACTION_TRIGGER_IDLE);
+ filter.addAction(ActivityManagerService.ACTION_TRIGGER_IDLE);
mContext.registerReceiver(this, filter);
}
mScreenOn = false;
mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
when, mIdleWindowSlop, mIdleTriggerIntent);
- } else if (action.equals(ACTION_TRIGGER_IDLE)) {
+ } else if (action.equals(ActivityManagerService.ACTION_TRIGGER_IDLE)) {
// idle time starts now. Do not set mIdle if screen is on.
if (!mIdle && !mScreenOn) {
if (DEBUG) {