Merge "Add app window unfold animation" into sc-v2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
59cc5f2f31
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021 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.
|
||||||
|
-->
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- Matches taskbar color -->
|
||||||
|
<item android:color="@android:color/system_neutral2_500" android:lStar="35" />
|
||||||
|
</selector>
|
||||||
@@ -27,6 +27,8 @@ import com.android.wm.shell.common.ShellExecutor;
|
|||||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||||
|
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
|
||||||
|
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
|
||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
||||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
@@ -52,6 +54,7 @@ public class ShellInitImpl {
|
|||||||
private final Optional<AppPairsController> mAppPairsOptional;
|
private final Optional<AppPairsController> mAppPairsOptional;
|
||||||
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
|
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
|
||||||
private final FullscreenTaskListener mFullscreenTaskListener;
|
private final FullscreenTaskListener mFullscreenTaskListener;
|
||||||
|
private final Optional<FullscreenUnfoldController> mFullscreenUnfoldController;
|
||||||
private final Optional<FreeformTaskListener> mFreeformTaskListenerOptional;
|
private final Optional<FreeformTaskListener> mFreeformTaskListenerOptional;
|
||||||
private final ShellExecutor mMainExecutor;
|
private final ShellExecutor mMainExecutor;
|
||||||
private final Transitions mTransitions;
|
private final Transitions mTransitions;
|
||||||
@@ -71,6 +74,7 @@ public class ShellInitImpl {
|
|||||||
Optional<AppPairsController> appPairsOptional,
|
Optional<AppPairsController> appPairsOptional,
|
||||||
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
||||||
FullscreenTaskListener fullscreenTaskListener,
|
FullscreenTaskListener fullscreenTaskListener,
|
||||||
|
Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
|
||||||
Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
|
Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
|
||||||
Transitions transitions,
|
Transitions transitions,
|
||||||
StartingWindowController startingWindow,
|
StartingWindowController startingWindow,
|
||||||
@@ -86,6 +90,7 @@ public class ShellInitImpl {
|
|||||||
mAppPairsOptional = appPairsOptional;
|
mAppPairsOptional = appPairsOptional;
|
||||||
mFullscreenTaskListener = fullscreenTaskListener;
|
mFullscreenTaskListener = fullscreenTaskListener;
|
||||||
mPipTouchHandlerOptional = pipTouchHandlerOptional;
|
mPipTouchHandlerOptional = pipTouchHandlerOptional;
|
||||||
|
mFullscreenUnfoldController = fullscreenUnfoldTransitionController;
|
||||||
mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
|
mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
|
||||||
mTransitions = transitions;
|
mTransitions = transitions;
|
||||||
mMainExecutor = mainExecutor;
|
mMainExecutor = mainExecutor;
|
||||||
@@ -128,6 +133,8 @@ public class ShellInitImpl {
|
|||||||
mFreeformTaskListenerOptional.ifPresent(f ->
|
mFreeformTaskListenerOptional.ifPresent(f ->
|
||||||
mShellTaskOrganizer.addListenerForType(
|
mShellTaskOrganizer.addListenerForType(
|
||||||
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
|
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
|
||||||
|
|
||||||
|
mFullscreenUnfoldController.ifPresent(FullscreenUnfoldController::init);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExternalThread
|
@ExternalThread
|
||||||
|
|||||||
@@ -14,25 +14,31 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.wm.shell;
|
package com.android.wm.shell.fullscreen;
|
||||||
|
|
||||||
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||||
|
|
||||||
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
|
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
|
||||||
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
|
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
|
import android.app.TaskInfo;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
import android.util.SparseBooleanArray;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.android.internal.protolog.common.ProtoLog;
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||||
import com.android.wm.shell.transition.Transitions;
|
import com.android.wm.shell.transition.Transitions;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Organizes tasks presented in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN}.
|
* Organizes tasks presented in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN}.
|
||||||
@@ -43,13 +49,17 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
|||||||
private final SyncTransactionQueue mSyncQueue;
|
private final SyncTransactionQueue mSyncQueue;
|
||||||
|
|
||||||
private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>();
|
private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>();
|
||||||
|
private final AnimatableTasksListener mAnimatableTasksListener = new AnimatableTasksListener();
|
||||||
|
private final FullscreenUnfoldController mFullscreenUnfoldController;
|
||||||
|
|
||||||
public FullscreenTaskListener(SyncTransactionQueue syncQueue) {
|
public FullscreenTaskListener(SyncTransactionQueue syncQueue,
|
||||||
|
Optional<FullscreenUnfoldController> unfoldController) {
|
||||||
mSyncQueue = syncQueue;
|
mSyncQueue = syncQueue;
|
||||||
|
mFullscreenUnfoldController = unfoldController.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
|
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
|
||||||
if (mDataByTaskId.get(taskInfo.taskId) != null) {
|
if (mDataByTaskId.get(taskInfo.taskId) != null) {
|
||||||
throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
|
throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
|
||||||
}
|
}
|
||||||
@@ -67,11 +77,16 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
|||||||
t.setMatrix(leash, 1, 0, 0, 1);
|
t.setMatrix(leash, 1, 0, 0, 1);
|
||||||
t.show(leash);
|
t.show(leash);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mAnimatableTasksListener.onTaskAppeared(taskInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
|
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
|
||||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
|
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
|
||||||
|
|
||||||
|
mAnimatableTasksListener.onTaskInfoChanged(taskInfo);
|
||||||
|
|
||||||
final TaskData data = mDataByTaskId.get(taskInfo.taskId);
|
final TaskData data = mDataByTaskId.get(taskInfo.taskId);
|
||||||
final Point positionInParent = taskInfo.positionInParent;
|
final Point positionInParent = taskInfo.positionInParent;
|
||||||
if (!positionInParent.equals(data.positionInParent)) {
|
if (!positionInParent.equals(data.positionInParent)) {
|
||||||
@@ -83,12 +98,15 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
|
public void onTaskVanished(RunningTaskInfo taskInfo) {
|
||||||
if (mDataByTaskId.get(taskInfo.taskId) == null) {
|
if (mDataByTaskId.get(taskInfo.taskId) == null) {
|
||||||
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
|
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mAnimatableTasksListener.onTaskVanished(taskInfo);
|
||||||
mDataByTaskId.remove(taskInfo.taskId);
|
mDataByTaskId.remove(taskInfo.taskId);
|
||||||
|
|
||||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
|
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
|
||||||
taskInfo.taskId);
|
taskInfo.taskId);
|
||||||
}
|
}
|
||||||
@@ -125,4 +143,65 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
|||||||
this.positionInParent = positionInParent;
|
this.positionInParent = positionInParent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AnimatableTasksListener {
|
||||||
|
private final SparseBooleanArray mTaskIds = new SparseBooleanArray();
|
||||||
|
|
||||||
|
public void onTaskAppeared(RunningTaskInfo taskInfo) {
|
||||||
|
final boolean isApplicable = isAnimatable(taskInfo);
|
||||||
|
if (isApplicable) {
|
||||||
|
mTaskIds.put(taskInfo.taskId, true);
|
||||||
|
|
||||||
|
if (mFullscreenUnfoldController != null) {
|
||||||
|
SurfaceControl leash = mDataByTaskId.get(taskInfo.taskId).surface;
|
||||||
|
mFullscreenUnfoldController.onTaskAppeared(taskInfo, leash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
|
||||||
|
final boolean isCurrentlyApplicable = mTaskIds.get(taskInfo.taskId);
|
||||||
|
final boolean isApplicable = isAnimatable(taskInfo);
|
||||||
|
|
||||||
|
if (isCurrentlyApplicable) {
|
||||||
|
if (isApplicable) {
|
||||||
|
// Still applicable, send update
|
||||||
|
if (mFullscreenUnfoldController != null) {
|
||||||
|
mFullscreenUnfoldController.onTaskInfoChanged(taskInfo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Became inapplicable
|
||||||
|
if (mFullscreenUnfoldController != null) {
|
||||||
|
mFullscreenUnfoldController.onTaskVanished(taskInfo);
|
||||||
|
}
|
||||||
|
mTaskIds.put(taskInfo.taskId, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isApplicable) {
|
||||||
|
// Became applicable
|
||||||
|
mTaskIds.put(taskInfo.taskId, true);
|
||||||
|
|
||||||
|
if (mFullscreenUnfoldController != null) {
|
||||||
|
SurfaceControl leash = mDataByTaskId.get(taskInfo.taskId).surface;
|
||||||
|
mFullscreenUnfoldController.onTaskAppeared(taskInfo, leash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTaskVanished(RunningTaskInfo taskInfo) {
|
||||||
|
final boolean isCurrentlyApplicable = mTaskIds.get(taskInfo.taskId);
|
||||||
|
if (isCurrentlyApplicable && mFullscreenUnfoldController != null) {
|
||||||
|
mFullscreenUnfoldController.onTaskVanished(taskInfo);
|
||||||
|
}
|
||||||
|
mTaskIds.put(taskInfo.taskId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAnimatable(TaskInfo taskInfo) {
|
||||||
|
// Filter all visible tasks that are not launcher tasks
|
||||||
|
// We do not animate launcher as it handles the animation by itself
|
||||||
|
return taskInfo != null && taskInfo.isVisible && taskInfo.getConfiguration()
|
||||||
|
.windowConfiguration.getActivityType() != ACTIVITY_TYPE_HOME;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.wm.shell.fullscreen;
|
||||||
|
|
||||||
|
import static android.graphics.Color.blue;
|
||||||
|
import static android.graphics.Color.green;
|
||||||
|
import static android.graphics.Color.red;
|
||||||
|
import static android.util.MathUtils.lerp;
|
||||||
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
|
|
||||||
|
import android.animation.RectEvaluator;
|
||||||
|
import android.animation.TypeEvaluator;
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.TaskInfo;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.InsetsSource;
|
||||||
|
import android.view.InsetsState;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
|
||||||
|
import com.android.internal.policy.ScreenDecorationsUtils;
|
||||||
|
import com.android.wm.shell.R;
|
||||||
|
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
|
||||||
|
import com.android.wm.shell.common.DisplayInsetsController;
|
||||||
|
import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
|
||||||
|
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
|
||||||
|
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls full screen app unfold transition: animating cropping window and scaling when
|
||||||
|
* folding or unfolding a foldable device.
|
||||||
|
*/
|
||||||
|
public final class FullscreenUnfoldController implements UnfoldListener,
|
||||||
|
OnInsetsChangedListener {
|
||||||
|
|
||||||
|
private static final float[] FLOAT_9 = new float[9];
|
||||||
|
private static final TypeEvaluator<Rect> RECT_EVALUATOR = new RectEvaluator(new Rect());
|
||||||
|
|
||||||
|
private static final float HORIZONTAL_START_MARGIN = 0.08f;
|
||||||
|
private static final float VERTICAL_START_MARGIN = 0.03f;
|
||||||
|
private static final float END_SCALE = 1f;
|
||||||
|
private static final float START_SCALE = END_SCALE - VERTICAL_START_MARGIN * 2;
|
||||||
|
private static final int BACKGROUND_LAYER_Z_INDEX = -1;
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final Executor mExecutor;
|
||||||
|
private final ShellUnfoldProgressProvider mProgressProvider;
|
||||||
|
private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
|
||||||
|
private final DisplayInsetsController mDisplayInsetsController;
|
||||||
|
|
||||||
|
private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>();
|
||||||
|
|
||||||
|
private SurfaceControl mBackgroundLayer;
|
||||||
|
private InsetsSource mTaskbarInsetsSource;
|
||||||
|
|
||||||
|
private final float mWindowCornerRadiusPx;
|
||||||
|
private final float[] mBackgroundColor;
|
||||||
|
private final float mExpandedTaskBarHeight;
|
||||||
|
|
||||||
|
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
|
||||||
|
|
||||||
|
public FullscreenUnfoldController(
|
||||||
|
@NonNull Context context,
|
||||||
|
@NonNull Executor executor,
|
||||||
|
@NonNull ShellUnfoldProgressProvider progressProvider,
|
||||||
|
@NonNull RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
|
||||||
|
@NonNull DisplayInsetsController displayInsetsController
|
||||||
|
) {
|
||||||
|
mContext = context;
|
||||||
|
mExecutor = executor;
|
||||||
|
mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
|
||||||
|
mProgressProvider = progressProvider;
|
||||||
|
mDisplayInsetsController = displayInsetsController;
|
||||||
|
mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context);
|
||||||
|
mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize(
|
||||||
|
com.android.internal.R.dimen.taskbar_frame_height);
|
||||||
|
mBackgroundColor = getBackgroundColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the controller
|
||||||
|
*/
|
||||||
|
public void init() {
|
||||||
|
mProgressProvider.addListener(mExecutor, this);
|
||||||
|
mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateChangeProgress(float progress) {
|
||||||
|
if (mAnimationContextByTaskId.size() == 0) return;
|
||||||
|
|
||||||
|
ensureBackground();
|
||||||
|
|
||||||
|
for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
|
||||||
|
final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
|
||||||
|
|
||||||
|
context.mCurrentCropRect.set(RECT_EVALUATOR
|
||||||
|
.evaluate(progress, context.mStartCropRect, context.mEndCropRect));
|
||||||
|
|
||||||
|
float scale = lerp(START_SCALE, END_SCALE, progress);
|
||||||
|
context.mMatrix.setScale(scale, scale, context.mCurrentCropRect.exactCenterX(),
|
||||||
|
context.mCurrentCropRect.exactCenterY());
|
||||||
|
|
||||||
|
mTransaction.setWindowCrop(context.mLeash, context.mCurrentCropRect)
|
||||||
|
.setMatrix(context.mLeash, context.mMatrix, FLOAT_9)
|
||||||
|
.setCornerRadius(context.mLeash, mWindowCornerRadiusPx);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTransaction.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateChangeFinished() {
|
||||||
|
for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
|
||||||
|
final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
|
||||||
|
resetSurface(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBackground();
|
||||||
|
mTransaction.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insetsChanged(InsetsState insetsState) {
|
||||||
|
mTaskbarInsetsSource = insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
|
||||||
|
for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
|
||||||
|
AnimationContext context = mAnimationContextByTaskId.valueAt(i);
|
||||||
|
context.update(mTaskbarInsetsSource, context.mTaskInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a new matching task appeared
|
||||||
|
*/
|
||||||
|
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
|
||||||
|
AnimationContext animationContext = new AnimationContext(leash, mTaskbarInsetsSource,
|
||||||
|
taskInfo);
|
||||||
|
mAnimationContextByTaskId.put(taskInfo.taskId, animationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when matching task changed
|
||||||
|
*/
|
||||||
|
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
|
||||||
|
AnimationContext animationContext = mAnimationContextByTaskId.get(taskInfo.taskId);
|
||||||
|
if (animationContext != null) {
|
||||||
|
animationContext.update(mTaskbarInsetsSource, taskInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when matching task vanished
|
||||||
|
*/
|
||||||
|
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
|
||||||
|
AnimationContext animationContext = mAnimationContextByTaskId.get(taskInfo.taskId);
|
||||||
|
if (animationContext != null) {
|
||||||
|
resetSurface(animationContext);
|
||||||
|
mAnimationContextByTaskId.remove(taskInfo.taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAnimationContextByTaskId.size() == 0) {
|
||||||
|
removeBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
mTransaction.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetSurface(AnimationContext context) {
|
||||||
|
mTransaction
|
||||||
|
.setWindowCrop(context.mLeash, null)
|
||||||
|
.setCornerRadius(context.mLeash, 0.0F)
|
||||||
|
.setMatrix(context.mLeash, 1.0F, 0.0F, 0.0F, 1.0F)
|
||||||
|
.setPosition(context.mLeash,
|
||||||
|
(float) context.mTaskInfo.positionInParent.x,
|
||||||
|
(float) context.mTaskInfo.positionInParent.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureBackground() {
|
||||||
|
if (mBackgroundLayer != null) return;
|
||||||
|
|
||||||
|
SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder()
|
||||||
|
.setName("app-unfold-background")
|
||||||
|
.setCallsite("AppUnfoldTransitionController")
|
||||||
|
.setColorLayer();
|
||||||
|
mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder);
|
||||||
|
mBackgroundLayer = colorLayerBuilder.build();
|
||||||
|
|
||||||
|
mTransaction
|
||||||
|
.setColor(mBackgroundLayer, mBackgroundColor)
|
||||||
|
.show(mBackgroundLayer)
|
||||||
|
.setLayer(mBackgroundLayer, BACKGROUND_LAYER_Z_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBackground() {
|
||||||
|
if (mBackgroundLayer == null) return;
|
||||||
|
if (mBackgroundLayer.isValid()) {
|
||||||
|
mTransaction.remove(mBackgroundLayer);
|
||||||
|
}
|
||||||
|
mBackgroundLayer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float[] getBackgroundColor() {
|
||||||
|
int colorInt = mContext.getResources().getColor(R.color.unfold_transition_background);
|
||||||
|
return new float[]{
|
||||||
|
(float) red(colorInt) / 255.0F,
|
||||||
|
(float) green(colorInt) / 255.0F,
|
||||||
|
(float) blue(colorInt) / 255.0F
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AnimationContext {
|
||||||
|
final SurfaceControl mLeash;
|
||||||
|
final Rect mStartCropRect = new Rect();
|
||||||
|
final Rect mEndCropRect = new Rect();
|
||||||
|
final Rect mCurrentCropRect = new Rect();
|
||||||
|
final Matrix mMatrix = new Matrix();
|
||||||
|
|
||||||
|
TaskInfo mTaskInfo;
|
||||||
|
|
||||||
|
private AnimationContext(SurfaceControl leash,
|
||||||
|
InsetsSource taskBarInsetsSource,
|
||||||
|
TaskInfo taskInfo) {
|
||||||
|
this.mLeash = leash;
|
||||||
|
update(taskBarInsetsSource, taskInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(InsetsSource taskBarInsetsSource, TaskInfo taskInfo) {
|
||||||
|
mTaskInfo = taskInfo;
|
||||||
|
mStartCropRect.set(mTaskInfo.getConfiguration().windowConfiguration.getBounds());
|
||||||
|
|
||||||
|
if (taskBarInsetsSource != null) {
|
||||||
|
// Only insets the cropping window with task bar when it's expanded
|
||||||
|
if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
|
||||||
|
mStartCropRect.inset(taskBarInsetsSource
|
||||||
|
.calculateVisibleInsets(mStartCropRect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mEndCropRect.set(mStartCropRect);
|
||||||
|
|
||||||
|
int horizontalMargin = (int) (mEndCropRect.width() * HORIZONTAL_START_MARGIN);
|
||||||
|
mStartCropRect.left = mEndCropRect.left + horizontalMargin;
|
||||||
|
mStartCropRect.right = mEndCropRect.right - horizontalMargin;
|
||||||
|
int verticalMargin = (int) (mEndCropRect.height() * VERTICAL_START_MARGIN);
|
||||||
|
mStartCropRect.top = mEndCropRect.top + verticalMargin;
|
||||||
|
mStartCropRect.bottom = mEndCropRect.bottom - verticalMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.wm.shell.unfold;
|
||||||
|
|
||||||
|
import android.annotation.FloatRange;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper interface for unfold transition progress provider for the Shell
|
||||||
|
* @see com.android.systemui.unfold.UnfoldTransitionProgressProvider
|
||||||
|
*/
|
||||||
|
public interface ShellUnfoldProgressProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a transition listener
|
||||||
|
*/
|
||||||
|
void addListener(Executor executor, UnfoldListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for receiving unfold updates
|
||||||
|
*/
|
||||||
|
interface UnfoldListener {
|
||||||
|
default void onStateChangeStarted() {}
|
||||||
|
|
||||||
|
default void onStateChangeProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
|
||||||
|
|
||||||
|
default void onStateChangeFinished() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.wm.shell.fullscreen;
|
||||||
|
|
||||||
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
|
import android.app.WindowConfiguration;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public class FullscreenTaskListenerTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SyncTransactionQueue mSyncQueue;
|
||||||
|
@Mock
|
||||||
|
private FullscreenUnfoldController mUnfoldController;
|
||||||
|
@Mock
|
||||||
|
private SurfaceControl mSurfaceControl;
|
||||||
|
|
||||||
|
private Optional<FullscreenUnfoldController> mFullscreenUnfoldController;
|
||||||
|
|
||||||
|
private FullscreenTaskListener mListener;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mFullscreenUnfoldController = Optional.of(mUnfoldController);
|
||||||
|
mListener = new FullscreenTaskListener(mSyncQueue, mFullscreenUnfoldController);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAnimatableTaskAppeared_notifiesUnfoldController() {
|
||||||
|
RunningTaskInfo info = createTaskInfo(/* visible */ true, /* taskId */ 0);
|
||||||
|
|
||||||
|
mListener.onTaskAppeared(info, mSurfaceControl);
|
||||||
|
|
||||||
|
verify(mUnfoldController).onTaskAppeared(eq(info), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleAnimatableTasksAppeared_notifiesUnfoldController() {
|
||||||
|
RunningTaskInfo animatable1 = createTaskInfo(/* visible */ true, /* taskId */ 0);
|
||||||
|
RunningTaskInfo animatable2 = createTaskInfo(/* visible */ true, /* taskId */ 1);
|
||||||
|
|
||||||
|
mListener.onTaskAppeared(animatable1, mSurfaceControl);
|
||||||
|
mListener.onTaskAppeared(animatable2, mSurfaceControl);
|
||||||
|
|
||||||
|
InOrder order = inOrder(mUnfoldController);
|
||||||
|
order.verify(mUnfoldController).onTaskAppeared(eq(animatable1), any());
|
||||||
|
order.verify(mUnfoldController).onTaskAppeared(eq(animatable2), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonAnimatableTaskAppeared_doesNotNotifyUnfoldController() {
|
||||||
|
RunningTaskInfo info = createTaskInfo(/* visible */ false, /* taskId */ 0);
|
||||||
|
|
||||||
|
mListener.onTaskAppeared(info, mSurfaceControl);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mUnfoldController);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonAnimatableTaskChanged_doesNotNotifyUnfoldController() {
|
||||||
|
RunningTaskInfo info = createTaskInfo(/* visible */ false, /* taskId */ 0);
|
||||||
|
mListener.onTaskAppeared(info, mSurfaceControl);
|
||||||
|
|
||||||
|
mListener.onTaskInfoChanged(info);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mUnfoldController);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonAnimatableTaskVanished_doesNotNotifyUnfoldController() {
|
||||||
|
RunningTaskInfo info = createTaskInfo(/* visible */ false, /* taskId */ 0);
|
||||||
|
mListener.onTaskAppeared(info, mSurfaceControl);
|
||||||
|
|
||||||
|
mListener.onTaskVanished(info);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mUnfoldController);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAnimatableTaskBecameInactive_notifiesUnfoldController() {
|
||||||
|
RunningTaskInfo animatableTask = createTaskInfo(/* visible */ true, /* taskId */ 0);
|
||||||
|
mListener.onTaskAppeared(animatableTask, mSurfaceControl);
|
||||||
|
RunningTaskInfo notAnimatableTask = createTaskInfo(/* visible */ false, /* taskId */ 0);
|
||||||
|
|
||||||
|
mListener.onTaskInfoChanged(notAnimatableTask);
|
||||||
|
|
||||||
|
verify(mUnfoldController).onTaskVanished(eq(notAnimatableTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAnimatableTaskVanished_notifiesUnfoldController() {
|
||||||
|
RunningTaskInfo taskInfo = createTaskInfo(/* visible */ true, /* taskId */ 0);
|
||||||
|
mListener.onTaskAppeared(taskInfo, mSurfaceControl);
|
||||||
|
|
||||||
|
mListener.onTaskVanished(taskInfo);
|
||||||
|
|
||||||
|
verify(mUnfoldController).onTaskVanished(eq(taskInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RunningTaskInfo createTaskInfo(boolean visible, int taskId) {
|
||||||
|
final RunningTaskInfo info = spy(new RunningTaskInfo());
|
||||||
|
info.isVisible = visible;
|
||||||
|
info.positionInParent = new Point();
|
||||||
|
when(info.getWindowingMode()).thenReturn(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
|
||||||
|
final Configuration configuration = new Configuration();
|
||||||
|
configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
|
||||||
|
when(info.getConfiguration()).thenReturn(configuration);
|
||||||
|
info.taskId = taskId;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,8 +24,6 @@ import android.app.INotificationManager;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.om.OverlayManager;
|
import android.content.om.OverlayManager;
|
||||||
import android.hardware.SensorManager;
|
|
||||||
import android.hardware.devicestate.DeviceStateManager;
|
|
||||||
import android.hardware.display.AmbientDisplayConfiguration;
|
import android.hardware.display.AmbientDisplayConfiguration;
|
||||||
import android.hardware.display.ColorDisplayManager;
|
import android.hardware.display.ColorDisplayManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -56,7 +54,6 @@ import com.android.systemui.dagger.qualifiers.Main;
|
|||||||
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
|
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||||
import com.android.systemui.keyguard.LifecycleScreenStatusProvider;
|
|
||||||
import com.android.systemui.qs.ReduceBrightColorsController;
|
import com.android.systemui.qs.ReduceBrightColorsController;
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
@@ -69,9 +66,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
|
|||||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||||
import com.android.systemui.statusbar.policy.NetworkController;
|
import com.android.systemui.statusbar.policy.NetworkController;
|
||||||
import com.android.systemui.theme.ThemeOverlayApplier;
|
import com.android.systemui.theme.ThemeOverlayApplier;
|
||||||
import com.android.systemui.unfold.UnfoldTransitionFactory;
|
|
||||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
|
|
||||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
|
|
||||||
import com.android.systemui.util.leak.LeakDetector;
|
import com.android.systemui.util.leak.LeakDetector;
|
||||||
import com.android.systemui.util.settings.SecureSettings;
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
@@ -284,37 +278,6 @@ public class DependencyProvider {
|
|||||||
return WindowManagerWrapper.getInstance();
|
return WindowManagerWrapper.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
|
||||||
@Provides
|
|
||||||
@SysUISingleton
|
|
||||||
public UnfoldTransitionProgressProvider provideUnfoldTransitionProgressProvider(
|
|
||||||
Context context,
|
|
||||||
UnfoldTransitionConfig config,
|
|
||||||
LifecycleScreenStatusProvider screenStatusProvider,
|
|
||||||
DeviceStateManager deviceStateManager,
|
|
||||||
SensorManager sensorManager,
|
|
||||||
@Main Executor executor,
|
|
||||||
@Main Handler handler
|
|
||||||
) {
|
|
||||||
return UnfoldTransitionFactory
|
|
||||||
.createUnfoldTransitionProgressProvider(
|
|
||||||
context,
|
|
||||||
config,
|
|
||||||
screenStatusProvider,
|
|
||||||
deviceStateManager,
|
|
||||||
sensorManager,
|
|
||||||
handler,
|
|
||||||
executor
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
@Provides
|
|
||||||
@SysUISingleton
|
|
||||||
public UnfoldTransitionConfig provideUnfoldTransitionConfig(Context context) {
|
|
||||||
return UnfoldTransitionFactory.createConfig(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@Provides
|
@Provides
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.android.internal.logging.UiEventLogger;
|
|||||||
import com.android.internal.logging.UiEventLoggerImpl;
|
import com.android.internal.logging.UiEventLoggerImpl;
|
||||||
import com.android.systemui.dagger.qualifiers.TestHarness;
|
import com.android.systemui.dagger.qualifiers.TestHarness;
|
||||||
import com.android.systemui.plugins.PluginsModule;
|
import com.android.systemui.plugins.PluginsModule;
|
||||||
|
import com.android.systemui.unfold.UnfoldTransitionModule;
|
||||||
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
|
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -49,6 +50,7 @@ import dagger.Provides;
|
|||||||
@Module(includes = {
|
@Module(includes = {
|
||||||
FrameworkServicesModule.class,
|
FrameworkServicesModule.class,
|
||||||
GlobalConcurrencyModule.class,
|
GlobalConcurrencyModule.class,
|
||||||
|
UnfoldTransitionModule.class,
|
||||||
PluginsModule.class,
|
PluginsModule.class,
|
||||||
})
|
})
|
||||||
public class GlobalModule {
|
public class GlobalModule {
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ package com.android.systemui.dump
|
|||||||
|
|
||||||
import android.util.ArrayMap
|
import android.util.ArrayMap
|
||||||
import com.android.systemui.Dumpable
|
import com.android.systemui.Dumpable
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
|
||||||
import com.android.systemui.log.LogBuffer
|
import com.android.systemui.log.LogBuffer
|
||||||
import java.io.FileDescriptor
|
import java.io.FileDescriptor
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintains a registry of things that should be dumped when a bug report is taken
|
* Maintains a registry of things that should be dumped when a bug report is taken
|
||||||
@@ -33,7 +33,7 @@ import javax.inject.Inject
|
|||||||
*
|
*
|
||||||
* See [DumpHandler] for more information on how and when this information is dumped.
|
* See [DumpHandler] for more information on how and when this information is dumped.
|
||||||
*/
|
*/
|
||||||
@SysUISingleton
|
@Singleton
|
||||||
open class DumpManager @Inject constructor() {
|
open class DumpManager @Inject constructor() {
|
||||||
private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap()
|
private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap()
|
||||||
private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap()
|
private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap()
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.systemui.keyguard
|
package com.android.systemui.keyguard
|
||||||
|
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
|
||||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
|
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
|
||||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
|
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@SysUISingleton
|
@Singleton
|
||||||
class LifecycleScreenStatusProvider @Inject constructor(screenLifecycle: ScreenLifecycle) :
|
class LifecycleScreenStatusProvider @Inject constructor(screenLifecycle: ScreenLifecycle) :
|
||||||
ScreenStatusProvider, ScreenLifecycle.Observer {
|
ScreenStatusProvider, ScreenLifecycle.Observer {
|
||||||
|
|
||||||
|
|||||||
@@ -19,18 +19,18 @@ package com.android.systemui.keyguard;
|
|||||||
import android.os.Trace;
|
import android.os.Trace;
|
||||||
|
|
||||||
import com.android.systemui.Dumpable;
|
import com.android.systemui.Dumpable;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks the screen lifecycle.
|
* Tracks the screen lifecycle.
|
||||||
*/
|
*/
|
||||||
@SysUISingleton
|
@Singleton
|
||||||
public class ScreenLifecycle extends Lifecycle<ScreenLifecycle.Observer> implements Dumpable {
|
public class ScreenLifecycle extends Lifecycle<ScreenLifecycle.Observer> implements Dumpable {
|
||||||
|
|
||||||
public static final int SCREEN_OFF = 0;
|
public static final int SCREEN_OFF = 0;
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.unfold
|
||||||
|
|
||||||
|
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||||
|
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
|
||||||
|
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
|
||||||
|
class ShellUnfoldProgressProvider(
|
||||||
|
private val unfoldProgressProvider: UnfoldTransitionProgressProvider
|
||||||
|
) : ShellUnfoldProgressProvider {
|
||||||
|
|
||||||
|
override fun addListener(executor: Executor, listener: UnfoldListener) {
|
||||||
|
unfoldProgressProvider.addCallback(object : TransitionProgressListener {
|
||||||
|
override fun onTransitionStarted() {
|
||||||
|
executor.execute {
|
||||||
|
listener.onStateChangeStarted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionProgress(progress: Float) {
|
||||||
|
executor.execute {
|
||||||
|
listener.onStateChangeProgress(progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionFinished() {
|
||||||
|
executor.execute {
|
||||||
|
listener.onStateChangeFinished()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.unfold
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.hardware.SensorManager
|
||||||
|
import android.hardware.devicestate.DeviceStateManager
|
||||||
|
import android.os.Handler
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.android.systemui.keyguard.LifecycleScreenStatusProvider
|
||||||
|
import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
||||||
|
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
|
||||||
|
import dagger.Lazy
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import java.util.Optional
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class UnfoldTransitionModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideUnfoldTransitionProgressProvider(
|
||||||
|
context: Context,
|
||||||
|
config: UnfoldTransitionConfig,
|
||||||
|
screenStatusProvider: LifecycleScreenStatusProvider,
|
||||||
|
deviceStateManager: DeviceStateManager,
|
||||||
|
sensorManager: SensorManager,
|
||||||
|
@Main executor: Executor,
|
||||||
|
@Main handler: Handler
|
||||||
|
): UnfoldTransitionProgressProvider =
|
||||||
|
createUnfoldTransitionProgressProvider(
|
||||||
|
context,
|
||||||
|
config,
|
||||||
|
screenStatusProvider,
|
||||||
|
deviceStateManager,
|
||||||
|
sensorManager,
|
||||||
|
handler,
|
||||||
|
executor
|
||||||
|
)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig =
|
||||||
|
createConfig(context)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideShellProgressProvider(
|
||||||
|
config: UnfoldTransitionConfig,
|
||||||
|
provider: Lazy<UnfoldTransitionProgressProvider>
|
||||||
|
): Optional<ShellUnfoldProgressProvider> =
|
||||||
|
if (config.isEnabled) {
|
||||||
|
Optional.ofNullable(ShellUnfoldProgressProvider(provider.get()))
|
||||||
|
} else {
|
||||||
|
Optional.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,6 @@ import com.android.internal.logging.UiEventLogger;
|
|||||||
import com.android.internal.statusbar.IStatusBarService;
|
import com.android.internal.statusbar.IStatusBarService;
|
||||||
import com.android.systemui.dagger.WMComponent;
|
import com.android.systemui.dagger.WMComponent;
|
||||||
import com.android.systemui.dagger.WMSingleton;
|
import com.android.systemui.dagger.WMSingleton;
|
||||||
import com.android.wm.shell.FullscreenTaskListener;
|
|
||||||
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
|
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
|
||||||
import com.android.wm.shell.ShellCommandHandler;
|
import com.android.wm.shell.ShellCommandHandler;
|
||||||
import com.android.wm.shell.ShellCommandHandlerImpl;
|
import com.android.wm.shell.ShellCommandHandlerImpl;
|
||||||
@@ -57,6 +56,8 @@ import com.android.wm.shell.common.annotations.ShellMainThread;
|
|||||||
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
|
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
|
||||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||||
|
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
|
||||||
|
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
|
||||||
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
|
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
|
||||||
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
|
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
|
||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||||
@@ -79,6 +80,7 @@ import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
|
|||||||
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelperController;
|
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelperController;
|
||||||
import com.android.wm.shell.transition.ShellTransitions;
|
import com.android.wm.shell.transition.ShellTransitions;
|
||||||
import com.android.wm.shell.transition.Transitions;
|
import com.android.wm.shell.transition.Transitions;
|
||||||
|
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -218,8 +220,28 @@ public abstract class WMShellBaseModule {
|
|||||||
|
|
||||||
@WMSingleton
|
@WMSingleton
|
||||||
@Provides
|
@Provides
|
||||||
static FullscreenTaskListener provideFullscreenTaskListener(SyncTransactionQueue syncQueue) {
|
static FullscreenTaskListener provideFullscreenTaskListener(
|
||||||
return new FullscreenTaskListener(syncQueue);
|
SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> controller) {
|
||||||
|
return new FullscreenTaskListener(syncQueue, controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Unfold transition
|
||||||
|
//
|
||||||
|
|
||||||
|
@WMSingleton
|
||||||
|
@Provides
|
||||||
|
static Optional<FullscreenUnfoldController> provideFullscreenUnfoldController(
|
||||||
|
Context context,
|
||||||
|
Optional<ShellUnfoldProgressProvider> progressProvider,
|
||||||
|
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
|
||||||
|
DisplayInsetsController displayInsetsController,
|
||||||
|
@ShellMainThread ShellExecutor mainExecutor
|
||||||
|
) {
|
||||||
|
return progressProvider.map(shellUnfoldTransitionProgressProvider ->
|
||||||
|
new FullscreenUnfoldController(context, mainExecutor,
|
||||||
|
shellUnfoldTransitionProgressProvider, rootTaskDisplayAreaOrganizer,
|
||||||
|
displayInsetsController));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -474,6 +496,7 @@ public abstract class WMShellBaseModule {
|
|||||||
Optional<AppPairsController> appPairsOptional,
|
Optional<AppPairsController> appPairsOptional,
|
||||||
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
||||||
FullscreenTaskListener fullscreenTaskListener,
|
FullscreenTaskListener fullscreenTaskListener,
|
||||||
|
Optional<FullscreenUnfoldController> appUnfoldTransitionController,
|
||||||
Optional<Optional<FreeformTaskListener>> freeformTaskListener,
|
Optional<Optional<FreeformTaskListener>> freeformTaskListener,
|
||||||
Transitions transitions,
|
Transitions transitions,
|
||||||
StartingWindowController startingWindow,
|
StartingWindowController startingWindow,
|
||||||
@@ -489,6 +512,7 @@ public abstract class WMShellBaseModule {
|
|||||||
appPairsOptional,
|
appPairsOptional,
|
||||||
pipTouchHandlerOptional,
|
pipTouchHandlerOptional,
|
||||||
fullscreenTaskListener,
|
fullscreenTaskListener,
|
||||||
|
appUnfoldTransitionController,
|
||||||
freeformTaskListener,
|
freeformTaskListener,
|
||||||
transitions,
|
transitions,
|
||||||
startingWindow,
|
startingWindow,
|
||||||
|
|||||||
Reference in New Issue
Block a user