Update SystemUIShared

This commit is contained in:
Suphon Thanakornpakapong
2021-10-07 08:38:54 +07:00
parent 3332a4e3ec
commit d1c4e1aaa9
51 changed files with 2299 additions and 1319 deletions
+6 -1
View File
@@ -1,4 +1,5 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion COMPILE_SDK
@@ -28,6 +29,10 @@ android {
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
}
kotlinOptions {
jvmTarget = '1.8'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@@ -37,5 +42,5 @@ android {
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
@@ -0,0 +1,146 @@
/*
* Copyright (C) 2020 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.shared.pip;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.Choreographer;
import android.view.SurfaceControl;
import android.window.PictureInPictureSurfaceTransaction;
/**
* TODO(b/171721389): unify this class with
* {@link com.android.wm.shell.pip.PipSurfaceTransactionHelper}, for instance, there should be one
* source of truth on enabling/disabling and the actual value of corner radius.
*/
public class PipSurfaceTransactionHelper {
private final int mCornerRadius;
private final Matrix mTmpTransform = new Matrix();
private final float[] mTmpFloat9 = new float[9];
private final RectF mTmpSourceRectF = new RectF();
private final RectF mTmpDestinationRectF = new RectF();
private final Rect mTmpDestinationRect = new Rect();
public PipSurfaceTransactionHelper(int cornerRadius) {
mCornerRadius = cornerRadius;
}
public PictureInPictureSurfaceTransaction scale(
SurfaceControl.Transaction tx, SurfaceControl leash,
Rect sourceBounds, Rect destinationBounds) {
float positionX = destinationBounds.left;
float positionY = destinationBounds.top;
mTmpSourceRectF.set(sourceBounds);
mTmpDestinationRectF.set(destinationBounds);
mTmpDestinationRectF.offsetTo(0, 0);
mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
.setCornerRadius(leash, cornerRadius);
return new PictureInPictureSurfaceTransaction(
positionX, positionY, mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scale(
SurfaceControl.Transaction tx, SurfaceControl leash,
Rect sourceBounds, Rect destinationBounds,
float degree, float positionX, float positionY) {
mTmpSourceRectF.set(sourceBounds);
mTmpDestinationRectF.set(destinationBounds);
mTmpDestinationRectF.offsetTo(0, 0);
mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
mTmpTransform.postRotate(degree, 0, 0);
final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
.setCornerRadius(leash, cornerRadius);
return new PictureInPictureSurfaceTransaction(
positionX, positionY, mTmpFloat9, degree, cornerRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scaleAndCrop(
SurfaceControl.Transaction tx, SurfaceControl leash,
Rect sourceBounds, Rect destinationBounds, Rect insets) {
mTmpSourceRectF.set(sourceBounds);
mTmpDestinationRect.set(sourceBounds);
mTmpDestinationRect.inset(insets);
// Scale by the shortest edge and offset such that the top/left of the scaled inset
// source rect aligns with the top/left of the destination bounds
final float scale = sourceBounds.width() <= sourceBounds.height()
? (float) destinationBounds.width() / sourceBounds.width()
: (float) destinationBounds.height() / sourceBounds.height();
final float left = destinationBounds.left - (insets.left + sourceBounds.left) * scale;
final float top = destinationBounds.top - (insets.top + sourceBounds.top) * scale;
mTmpTransform.setScale(scale, scale);
final float cornerRadius = getScaledCornerRadius(mTmpDestinationRect, destinationBounds);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, left, top)
.setCornerRadius(leash, cornerRadius);
return new PictureInPictureSurfaceTransaction(
left, top, mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect);
}
public PictureInPictureSurfaceTransaction scaleAndRotate(
SurfaceControl.Transaction tx, SurfaceControl leash,
Rect sourceBounds, Rect destinationBounds, Rect insets,
float degree, float positionX, float positionY) {
mTmpSourceRectF.set(sourceBounds);
mTmpDestinationRect.set(sourceBounds);
mTmpDestinationRect.inset(insets);
// Scale by the shortest edge and offset such that the top/left of the scaled inset
// source rect aligns with the top/left of the destination bounds
final float scale = sourceBounds.width() <= sourceBounds.height()
? (float) destinationBounds.width() / sourceBounds.width()
: (float) destinationBounds.height() / sourceBounds.height();
mTmpTransform.setRotate(degree, 0, 0);
mTmpTransform.postScale(scale, scale);
final float cornerRadius = getScaledCornerRadius(mTmpDestinationRect, destinationBounds);
// adjust the positions, take account also the insets
final float adjustedPositionX, adjustedPositionY;
if (degree < 0) {
adjustedPositionX = positionX + insets.top * scale;
adjustedPositionY = positionY + insets.left * scale;
} else {
adjustedPositionX = positionX - insets.top * scale;
adjustedPositionY = positionY - insets.left * scale;
}
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, adjustedPositionX, adjustedPositionY)
.setCornerRadius(leash, cornerRadius);
return new PictureInPictureSurfaceTransaction(
adjustedPositionX, adjustedPositionY,
mTmpFloat9, degree, cornerRadius, mTmpDestinationRect);
}
/** @return the round corner radius scaled by given from and to bounds */
private float getScaledCornerRadius(Rect fromBounds, Rect toBounds) {
final float scale = (float) (Math.hypot(fromBounds.width(), fromBounds.height())
/ Math.hypot(toBounds.width(), toBounds.height()));
return mCornerRadius * scale;
}
/** @return {@link SurfaceControl.Transaction} instance with vsync-id */
public static SurfaceControl.Transaction newSurfaceControlTransaction() {
final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
return tx;
}
}
@@ -24,9 +24,9 @@ public interface PluginEnabler {
int ENABLED = 0;
int DISABLED_MANUALLY = 1;
int DISABLED_INVALID_VERSION = 1;
int DISABLED_FROM_EXPLICIT_CRASH = 2;
int DISABLED_FROM_SYSTEM_CRASH = 3;
int DISABLED_INVALID_VERSION = 2;
int DISABLED_FROM_EXPLICIT_CRASH = 3;
int DISABLED_FROM_SYSTEM_CRASH = 4;
@IntDef({ENABLED, DISABLED_MANUALLY, DISABLED_INVALID_VERSION, DISABLED_FROM_EXPLICIT_CRASH,
DISABLED_FROM_SYSTEM_CRASH})
@@ -37,4 +37,9 @@ public interface PluginInitializer {
* Called from {@link PluginManagerImpl#handleWtfs()}.
*/
void handleWtfs();
/**
* Returns if pluging manager should run in debug mode.
*/
boolean isDebuggable();
}
@@ -28,7 +28,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -72,7 +71,7 @@ public class PluginInstanceManager<T extends Plugin> {
PluginInstanceManager(Context context, String action, PluginListener<T> listener,
boolean allowMultiple, Looper looper, VersionInfo version, PluginManagerImpl manager) {
this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
manager, Build.IS_DEBUGGABLE, manager.getWhitelistedPlugins());
manager, manager.isDebuggable(), manager.getWhitelistedPlugins());
}
@VisibleForTesting
@@ -386,7 +385,8 @@ public class PluginInstanceManager<T extends Plugin> {
}
Intent i = new Intent(PluginManagerImpl.DISABLE_PLUGIN).setData(
Uri.parse("package://" + component.flattenToString()));
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i,
PendingIntent.FLAG_IMMUTABLE);
nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
mContext.getSystemService(NotificationManager.class)
.notify(SystemMessage.NOTE_PLUGIN, nb.build());
@@ -66,8 +66,6 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private static final String TAG = PluginManagerImpl.class.getSimpleName();
static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
private static PluginManager sInstance;
private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
= new ArrayMap<>();
private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
@@ -75,7 +73,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
private final Context mContext;
private final PluginInstanceManagerFactory mFactory;
private final boolean isDebuggable;
private final boolean mIsDebuggable;
private final PluginPrefs mPluginPrefs;
private final PluginEnabler mPluginEnabler;
private final PluginInitializer mPluginInitializer;
@@ -85,7 +83,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private Looper mLooper;
public PluginManagerImpl(Context context, PluginInitializer initializer) {
this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE,
this(context, new PluginInstanceManagerFactory(), initializer.isDebuggable(),
(UncaughtExceptionHandler) invoke(sGetUncaughtExceptionPreHandler, null), initializer);
}
@@ -95,7 +93,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
mContext = context;
mFactory = factory;
mLooper = initializer.getBgLooper();
isDebuggable = debuggable;
mIsDebuggable = debuggable;
mWhitelistedPlugins.addAll(Arrays.asList(initializer.getWhitelistedPlugins(mContext)));
mPluginPrefs = new PluginPrefs(mContext);
mPluginEnabler = initializer.getPluginEnabler(mContext);
@@ -113,6 +111,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
});
}
public boolean isDebuggable() {
return mIsDebuggable;
}
public String[] getWhitelistedPlugins() {
return mWhitelistedPlugins.toArray(new String[0]);
}
@@ -197,10 +199,12 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(this, filter);
filter.addAction(PLUGIN_CHANGED);
filter.addAction(DISABLE_PLUGIN);
filter.addDataScheme("package");
mContext.registerReceiver(this, filter);
mContext.registerReceiver(this, filter, PluginInstanceManager.PLUGIN_PERMISSION, null);
filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiver(this, filter);
}
@@ -259,7 +263,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
.setContentText("Restart SysUI for changes to take effect.");
Intent i = new Intent("com.android.systemui.action.RESTART").setData(
Uri.parse("package://" + pkg));
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, PendingIntent.FLAG_MUTABLE_UNAUDITED);
nb.addAction(new Action.Builder(null, "Restart SysUI", pi).build());
mContext.getSystemService(NotificationManager.class)
.notify(SystemMessage.NOTE_PLUGIN, nb.build());
@@ -299,7 +303,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
/** Returns class loader specific for the given plugin. */
public ClassLoader getClassLoader(ApplicationInfo appInfo) {
if (!isDebuggable && !isPluginPackageWhitelisted(appInfo.packageName)) {
if (!mIsDebuggable && !isPluginPackageWhitelisted(appInfo.packageName)) {
Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:"
+ appInfo.sourceDir + ", pkg: " + appInfo.packageName);
return null;
@@ -75,4 +75,10 @@ oneway interface IOverviewProxy {
* Sent when the split screen is resized
*/
void onSplitScreenSecondaryBoundsChanged(in Rect bounds, in Rect insets) = 17;
/**
* Sent IME status changes
*/
void onImeWindowStatusChanged(int displayId, IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) = 18;
}
@@ -20,34 +20,22 @@ import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.MotionEvent;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteTransitionCompat;
/**
* Temporary callbacks into SystemUI.
* Next id = 27
*/
interface ISystemUiProxy {
/**
* Proxies SurfaceControl.screenshotToBuffer().
* @Removed
* GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
* int maxLayer, boolean useIdentityTransform, int rotation) = 0;
*/
/**
* Begins screen pinning on the provided {@param taskId}.
*/
void startScreenPinning(int taskId) = 1;
/**
* Notifies SystemUI that split screen has been invoked.
*/
void onSplitScreenInvoked() = 5;
/**
* Notifies SystemUI that Overview is shown.
*/
@@ -58,16 +46,10 @@ interface ISystemUiProxy {
*/
Rect getNonMinimizedSplitScreenSecondaryBounds() = 7;
/**
* Control the {@param alpha} of the back button in the navigation bar and {@param animate} if
* needed from current value
* @deprecated
*/
void setBackButtonAlpha(float alpha, boolean animate) = 8;
/**
* Control the {@param alpha} of the option nav bar button (back-button in 2 button mode
* and home bar in no-button mode) and {@param animate} if needed from current value
* and home handle & background in gestural mode). The {@param animate} is currently only
* supported for 2 button mode.
*/
void setNavBarButtonAlpha(float alpha, boolean animate) = 19;
@@ -96,11 +78,6 @@ interface ISystemUiProxy {
*/
void startAssistant(in Bundle bundle) = 13;
/**
* Creates a new gesture monitor
*/
Bundle monitorGestureInput(String name, int displayId) = 14;
/**
* Notifies that the accessibility button in the system's navigation area has been clicked
*/
@@ -116,11 +93,6 @@ interface ISystemUiProxy {
*/
void stopScreenPinning() = 17;
/**
* Sets the shelf height and visibility.
*/
void setShelfHeight(boolean visible, int shelfHeight) = 20;
/**
* Handle the provided image as if it was a screenshot.
*
@@ -140,20 +112,33 @@ interface ISystemUiProxy {
*/
void notifySwipeToHomeFinished() = 23;
/**
* Sets listener to get pinned stack animation callbacks.
*/
void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) = 24;
/**
* Notifies that quickstep will switch to a new task
* @param rotation indicates which Surface.Rotation the gesture was started in
*/
void onQuickSwitchToNewTask(int rotation) = 25;
void notifyPrioritizedRotation(int rotation) = 25;
/**
* Handle the provided image as if it was a screenshot.
*/
void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen,
in Insets visibleInsets, in Task.TaskKey task) = 26;
in Insets visibleInsets, in Task.TaskKey task) = 28;
/**
* Notifies to expand notification panel.
*/
void expandNotificationPanel() = 29;
/**
* Notifies SystemUI to invoke Back.
*/
void onBackPressed() = 44;
/** Sets home rotation enabled. */
void setHomeRotationEnabled(boolean enabled) = 45;
/** Notifies that a swipe-up gesture has started */
oneway void notifySwipeUpGestureStarted() = 46;
// Next id = 47
}
@@ -43,17 +43,6 @@ public class Task {
public static final String TAG = "Task";
/* Task callbacks */
@Deprecated
public interface TaskCallbacks {
/* Notifies when a task has been bound */
void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
/* Notifies when a task has been unbound */
void onTaskDataUnloaded();
/* Notifies when a task's windowing mode has changed. */
void onTaskWindowingModeChanged();
}
/**
* The Task Key represents the unique primary key for the task
*/
@@ -208,12 +197,6 @@ public class Task {
@ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
public TaskKey key;
/**
* The temporary sort index in the stack, used when ordering the stack.
*/
@Deprecated
public int temporarySortIndexInStack;
/**
* The icon is the task description icon (if provided), which falls back to the activity icon,
* which can then fall back to the application icon.
@@ -229,45 +212,24 @@ public class Task {
public int colorPrimary;
@ViewDebug.ExportedProperty(category="recents")
public int colorBackground;
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public boolean useLightOnPrimaryColor;
/**
* The task description for this task, only used to reload task icons.
*/
public TaskDescription taskDescription;
/**
* The state isLaunchTarget will be set for the correct task upon launching Recents.
*/
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public boolean isLaunchTarget;
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public boolean isStackTask;
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public boolean isSystemApp;
@ViewDebug.ExportedProperty(category="recents")
public boolean isDockable;
/**
* Resize mode. See {@link ActivityInfo#resizeMode}.
*/
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public int resizeMode;
@ViewDebug.ExportedProperty(category="recents")
public ComponentName topActivity;
@ViewDebug.ExportedProperty(category="recents")
public boolean isLocked;
@Deprecated
private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
// Last snapshot data, only used for recent tasks
public ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
new ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData();
public Task() {
// Do nothing
@@ -289,6 +251,16 @@ public class Task {
this.taskDescription = new TaskDescription();
}
public Task(Task other) {
this(other.key, other.colorPrimary, other.colorBackground, other.isDockable,
other.isLocked, other.taskDescription, other.topActivity);
lastSnapshotData.set(other.lastSnapshotData);
}
/**
* Use {@link Task#Task(Task)}.
*/
@Deprecated
public Task(TaskKey key, int colorPrimary, int colorBackground,
boolean isDockable, boolean isLocked, TaskDescription taskDescription,
ComponentName topActivity) {
@@ -301,103 +273,6 @@ public class Task {
this.topActivity = topActivity;
}
@Deprecated
public Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title,
String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget,
boolean isStackTask, boolean isSystemApp, boolean isDockable,
TaskDescription taskDescription, int resizeMode, ComponentName topActivity,
boolean isLocked) {
this.key = key;
this.icon = icon;
this.thumbnail = thumbnail;
this.title = title;
this.titleDescription = titleDescription;
this.colorPrimary = colorPrimary;
this.colorBackground = colorBackground;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
Color.WHITE) > 3f;
this.taskDescription = taskDescription;
this.isLaunchTarget = isLaunchTarget;
this.isStackTask = isStackTask;
this.isSystemApp = isSystemApp;
this.isDockable = isDockable;
this.resizeMode = resizeMode;
this.topActivity = topActivity;
this.isLocked = isLocked;
}
/**
* Copies the metadata from another task, but retains the current callbacks.
*/
@Deprecated
public void copyFrom(Task o) {
this.key = o.key;
this.icon = o.icon;
this.thumbnail = o.thumbnail;
this.title = o.title;
this.titleDescription = o.titleDescription;
this.colorPrimary = o.colorPrimary;
this.colorBackground = o.colorBackground;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
this.taskDescription = o.taskDescription;
this.isLaunchTarget = o.isLaunchTarget;
this.isStackTask = o.isStackTask;
this.isSystemApp = o.isSystemApp;
this.isDockable = o.isDockable;
this.resizeMode = o.resizeMode;
this.isLocked = o.isLocked;
this.topActivity = o.topActivity;
}
/**
* Add a callback.
*/
@Deprecated
public void addCallback(TaskCallbacks cb) {
if (!mCallbacks.contains(cb)) {
mCallbacks.add(cb);
}
}
/**
* Remove a callback.
*/
@Deprecated
public void removeCallback(TaskCallbacks cb) {
mCallbacks.remove(cb);
}
/** Updates the task's windowing mode. */
@Deprecated
public void setWindowingMode(int windowingMode) {
key.setWindowingMode(windowingMode);
int callbackCount = mCallbacks.size();
for (int i = 0; i < callbackCount; i++) {
mCallbacks.get(i).onTaskWindowingModeChanged();
}
}
/** Notifies the callback listeners that this task has been loaded */
@Deprecated
public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) {
this.icon = applicationIcon;
this.thumbnail = thumbnailData;
int callbackCount = mCallbacks.size();
for (int i = 0; i < callbackCount; i++) {
mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData);
}
}
/** Notifies the callback listeners that this task has been unloaded */
@Deprecated
public void notifyTaskDataUnloaded(Drawable defaultApplicationIcon) {
icon = defaultApplicationIcon;
thumbnail = null;
for (int i = mCallbacks.size() - 1; i >= 0; i--) {
mCallbacks.get(i).onTaskDataUnloaded();
}
}
/**
* Returns the top activity component.
*/
@@ -407,6 +282,29 @@ public class Task {
: key.baseIntent.getComponent();
}
public void setLastSnapshotData(ActivityManager.RecentTaskInfo rawTask) {
lastSnapshotData.set(rawTask.lastSnapshotData);
}
/**
* Returns the visible width to height ratio. Returns 0f if snapshot data is not available.
*/
public float getVisibleThumbnailRatio(boolean clipInsets) {
if (lastSnapshotData.taskSize == null || lastSnapshotData.contentInsets == null) {
return 0f;
}
float availableWidth = lastSnapshotData.taskSize.x;
float availableHeight = lastSnapshotData.taskSize.y;
if (clipInsets) {
availableWidth -=
(lastSnapshotData.contentInsets.left + lastSnapshotData.contentInsets.right);
availableHeight -=
(lastSnapshotData.contentInsets.top + lastSnapshotData.contentInsets.bottom);
}
return availableWidth / availableHeight;
}
@Override
public boolean equals(Object o) {
// Check that the id matches
@@ -424,9 +322,6 @@ public class Task {
if (!isDockable) {
writer.print(" dockable=N");
}
if (isLaunchTarget) {
writer.print(" launchTarget=Y");
}
if (isLocked) {
writer.print(" locked=Y");
}
@@ -22,14 +22,14 @@ import static android.graphics.Bitmap.Config.ARGB_8888;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_UNDEFINED;
import android.app.ActivityManager.TaskSnapshot;
import android.window.TaskSnapshot;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.util.Log;
import android.view.WindowInsetsController.Appearance;
/**
* Data for a single thumbnail.
@@ -44,7 +44,7 @@ public class ThumbnailData {
public boolean isRealSnapshot;
public boolean isTranslucent;
public int windowingMode;
public int systemUiVisibility;
public @Appearance int appearance;
public float scale;
public long snapshotId;
@@ -58,22 +58,30 @@ public class ThumbnailData {
isRealSnapshot = true;
isTranslucent = false;
windowingMode = WINDOWING_MODE_UNDEFINED;
systemUiVisibility = 0;
snapshotId = 0;
}
public ThumbnailData(TaskSnapshot snapshot) {
final GraphicBuffer buffer = snapshot.getSnapshot();
if (buffer == null || (buffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
private static Bitmap makeThumbnail(TaskSnapshot snapshot) {
Bitmap thumbnail = null;
try (final HardwareBuffer buffer = snapshot.getHardwareBuffer()) {
if (buffer != null) {
thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());
}
} catch (IllegalArgumentException ex) {
// TODO(b/157562905): Workaround for a crash when we get a snapshot without this state
Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: "
+ buffer);
+ snapshot.getHardwareBuffer(), ex);
}
if (thumbnail == null) {
Point taskSize = snapshot.getTaskSize();
thumbnail = Bitmap.createBitmap(taskSize.x, taskSize.y, ARGB_8888);
thumbnail.eraseColor(Color.BLACK);
} else {
thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());
}
return thumbnail;
}
public ThumbnailData(TaskSnapshot snapshot) {
thumbnail = makeThumbnail(snapshot);
insets = new Rect(snapshot.getContentInsets());
orientation = snapshot.getOrientation();
rotation = snapshot.getRotation();
@@ -84,7 +92,7 @@ public class ThumbnailData {
isRealSnapshot = snapshot.isRealSnapshot();
isTranslucent = snapshot.isTranslucent();
windowingMode = snapshot.getWindowingMode();
systemUiVisibility = snapshot.getSystemUiVisibility();
appearance = snapshot.getAppearance();
snapshotId = snapshot.getId();
}
}
@@ -81,6 +81,7 @@ public final class BitmapUtil {
HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer), colorSpace);
return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
colorSpace.getColorSpace());
}
}
@@ -36,6 +36,6 @@ public class AppTransitionAnimationSpecCompat {
public AppTransitionAnimationSpec toAppTransitionAnimationSpec() {
return new AppTransitionAnimationSpec(mTaskId,
mBuffer != null ? mBuffer.createGraphicBufferHandle() : null, mRect);
mBuffer != null ? mBuffer.getHardwareBuffer() : null, mRect);
}
}
@@ -20,39 +20,31 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.ActivityTaskManager.getService;
import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.TaskSnapshot;
import android.window.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.IRecentsAnimationController;
@@ -61,12 +53,9 @@ import android.view.RemoteAnimationTarget;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.function.Consumer;
public class ActivityManagerWrapper {
@@ -82,16 +71,8 @@ public class ActivityManagerWrapper {
// Should match the value in AssistManager
private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";
private final PackageManager mPackageManager;
private final BackgroundExecutor mBackgroundExecutor;
private final TaskStackChangeListeners mTaskStackChangeListeners;
private ActivityManagerWrapper() {
final Context context = AppGlobals.getInitialApplication();
mPackageManager = context.getPackageManager();
mBackgroundExecutor = BackgroundExecutor.get();
mTaskStackChangeListeners = new TaskStackChangeListeners(Looper.getMainLooper());
}
private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
private ActivityManagerWrapper() { }
public static ActivityManagerWrapper getInstance() {
return sInstance;
@@ -123,38 +104,28 @@ public class ActivityManagerWrapper {
*/
public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
// Note: The set of running tasks from the system is ordered by recency
try {
List<ActivityManager.RunningTaskInfo> tasks =
ActivityTaskManager.getService().getFilteredTasks(1, filterOnlyVisibleRecents);
if (tasks.isEmpty()) {
return null;
}
return tasks.get(0);
} catch (RemoteException e) {
List<ActivityManager.RunningTaskInfo> tasks =
mAtm.getTasks(1, filterOnlyVisibleRecents);
if (tasks.isEmpty()) {
return null;
}
return tasks.get(0);
}
/**
* @return a list of the recents tasks.
*/
public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
try {
return ActivityTaskManager.getService().getRecentTasks(numTasks,
RECENT_IGNORE_UNAVAILABLE, userId).getList();
} catch (RemoteException e) {
Log.e(TAG, "Failed to get recent tasks", e);
return new ArrayList<>();
}
return mAtm.getRecentTasks(numTasks, RECENT_IGNORE_UNAVAILABLE, userId);
}
/**
* @return the task snapshot for the given {@param taskId}.
*/
public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
ActivityManager.TaskSnapshot snapshot = null;
TaskSnapshot snapshot = null;
try {
snapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId, isLowResolution);
snapshot = getService().getTaskSnapshot(taskId, isLowResolution);
} catch (RemoteException e) {
Log.w(TAG, "Failed to retrieve task snapshot", e);
}
@@ -169,80 +140,37 @@ public class ActivityManagerWrapper {
* Removes the outdated snapshot of home task.
*/
public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
mBackgroundExecutor.submit(new Runnable() {
@Override
public void run() {
try {
ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
homeActivity.getActivityToken());
} catch (RemoteException e) {
Log.w(TAG, "Failed to invalidate home snapshot", e);
}
}
});
}
/**
* @return the activity label, badging if necessary.
*/
public String getBadgedActivityLabel(ActivityInfo info, int userId) {
return getBadgedLabel(info.loadLabel(mPackageManager).toString(), userId);
}
/**
* @return the application label, badging if necessary.
*/
public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
return getBadgedLabel(appInfo.loadLabel(mPackageManager).toString(), userId);
}
/**
* @return the content description for a given task, badging it if necessary. The content
* description joins the app and activity labels.
*/
public String getBadgedContentDescription(ActivityInfo info, int userId,
ActivityManager.TaskDescription td) {
String activityLabel;
if (td != null && td.getLabel() != null) {
activityLabel = td.getLabel();
} else {
activityLabel = info.loadLabel(mPackageManager).toString();
try {
ActivityClient.getInstance().invalidateHomeTaskSnapshot(
homeActivity.getActivityToken());
} catch (Throwable e) {
Log.w(TAG, "Failed to invalidate home snapshot", e);
}
String applicationLabel = info.applicationInfo.loadLabel(mPackageManager).toString();
String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
return applicationLabel.equals(activityLabel)
? badgedApplicationLabel
: badgedApplicationLabel + " " + activityLabel;
}
/**
* @return the given label for a user, badging if necessary.
*/
private String getBadgedLabel(String label, int userId) {
if (userId != UserHandle.myUserId()) {
label = mPackageManager.getUserBadgedLabel(label, new UserHandle(userId)).toString();
}
return label;
}
/**
* Starts the recents activity. The caller should manage the thread on which this is called.
*/
public void startRecentsActivity(Intent intent, final AssistDataReceiver assistDataReceiver,
public void startRecentsActivity(Intent intent, long eventTime,
final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
Handler resultCallbackHandler) {
boolean result = startRecentsActivity(intent, eventTime, animationHandler);
if (resultCallback != null) {
resultCallbackHandler.post(new Runnable() {
@Override
public void run() {
resultCallback.accept(result);
}
});
}
}
/**
* Starts the recents activity. The caller should manage the thread on which this is called.
*/
public boolean startRecentsActivity(
Intent intent, long eventTime, RecentsAnimationListener animationHandler) {
try {
IAssistDataReceiver receiver = null;
if (assistDataReceiver != null) {
receiver = new IAssistDataReceiver.Stub() {
public void onHandleAssistData(Bundle resultData) {
assistDataReceiver.onHandleAssistData(resultData);
}
public void onHandleAssistScreenshot(Bitmap screenshot) {
assistDataReceiver.onHandleAssistScreenshot(screenshot);
}
};
}
IRecentsAnimationRunner runner = null;
if (animationHandler != null) {
runner = new IRecentsAnimationRunner.Stub() {
@@ -272,100 +200,58 @@ public class ActivityManagerWrapper {
}
};
}
ActivityTaskManager.getService().startRecentsActivity(intent, receiver, runner);
if (resultCallback != null) {
resultCallbackHandler.post(new Runnable() {
@Override
public void run() {
resultCallback.accept(true);
}
});
}
getService().startRecentsActivity(intent, eventTime, runner);
return true;
} catch (Exception e) {
if (resultCallback != null) {
resultCallbackHandler.post(new Runnable() {
@Override
public void run() {
resultCallback.accept(false);
}
});
}
return false;
}
}
/**
* Cancels the remote recents animation started from {@link #startRecentsActivity}.
*/
public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
try {
ActivityTaskManager.getService().cancelRecentsAnimation(restoreHomeStackPosition);
getService().cancelRecentsAnimation(restoreHomeRootTaskPosition);
} catch (RemoteException e) {
Log.e(TAG, "Failed to cancel recents animation", e);
}
}
/**
* Starts a task from Recents.
*
* @see {@link #startActivityFromRecentsAsync(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
*/
public void startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options,
Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
startActivityFromRecentsAsync(taskKey, options, WINDOWING_MODE_UNDEFINED,
ACTIVITY_TYPE_UNDEFINED, resultCallback, resultCallbackHandler);
}
/**
* Starts a task from Recents.
*
* @param resultCallback The result success callback
* @param resultCallbackHandler The handler to receive the result callback
*/
public void startActivityFromRecentsAsync(final Task.TaskKey taskKey, ActivityOptions options,
int windowingMode, int activityType, final Consumer<Boolean> resultCallback,
final Handler resultCallbackHandler) {
if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// We show non-visible docked tasks in Recents, but we always want to launch
// them in the fullscreen stack.
if (options == null) {
options = ActivityOptions.makeBasic();
}
options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
} else if (windowingMode != WINDOWING_MODE_UNDEFINED
|| activityType != ACTIVITY_TYPE_UNDEFINED) {
if (options == null) {
options = ActivityOptions.makeBasic();
}
options.setLaunchWindowingMode(windowingMode);
options.setLaunchActivityType(activityType);
}
final ActivityOptions finalOptions = options;
boolean result = false;
try {
result = startActivityFromRecents(taskKey.id, finalOptions);
} catch (Exception e) {
// Fall through
}
final boolean finalResult = result;
public void startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options,
Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
final boolean result = startActivityFromRecents(taskKey, options);
if (resultCallback != null) {
resultCallbackHandler.post(new Runnable() {
@Override
public void run() {
resultCallback.accept(finalResult);
resultCallback.accept(result);
}
});
}
}
/**
* Starts a task from Recents synchronously.
*/
public boolean startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options) {
ActivityOptionsCompat.addTaskInfo(options, taskKey);
return startActivityFromRecents(taskKey.id, options);
}
/**
* Starts a task from Recents synchronously.
*/
public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
try {
Bundle optsBundle = options == null ? null : options.toBundle();
ActivityTaskManager.getService().startActivityFromRecents(taskId, optsBundle);
getService().startActivityFromRecents(taskId, optsBundle);
return true;
} catch (Exception e) {
return false;
@@ -373,94 +259,49 @@ public class ActivityManagerWrapper {
}
/**
* Moves an already resumed task to the side of the screen to initiate split screen.
*/
public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
Rect initialBounds) {
try {
return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(taskId,
true /* onTop */);
} catch (RemoteException e) {
return false;
}
}
/**
* Registers a task stack listener with the system.
* This should be called on the main thread.
* @deprecated use {@link TaskStackChangeListeners#registerTaskStackListener}
*/
public void registerTaskStackListener(TaskStackChangeListener listener) {
synchronized (mTaskStackChangeListeners) {
mTaskStackChangeListeners.addListener(ActivityManager.getService(), listener);
}
TaskStackChangeListeners.getInstance().registerTaskStackListener(listener);
}
/**
* Unregisters a task stack listener with the system.
* This should be called on the main thread.
* @deprecated use {@link TaskStackChangeListeners#unregisterTaskStackListener}
*/
public void unregisterTaskStackListener(TaskStackChangeListener listener) {
synchronized (mTaskStackChangeListeners) {
mTaskStackChangeListeners.removeListener(listener);
}
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(listener);
}
/**
* Requests that the system close any open system windows (including other SystemUI).
*/
public Future<?> closeSystemWindows(final String reason) {
return mBackgroundExecutor.submit(new Runnable() {
@Override
public void run() {
try {
ActivityManager.getService().closeSystemDialogs(reason);
} catch (RemoteException e) {
Log.w(TAG, "Failed to close system windows", e);
}
}
});
public void closeSystemWindows(final String reason) {
try {
ActivityManager.getService().closeSystemDialogs(reason);
} catch (RemoteException e) {
Log.w(TAG, "Failed to close system windows", e);
}
}
/**
* Removes a task by id.
*/
public void removeTask(final int taskId) {
mBackgroundExecutor.submit(new Runnable() {
@Override
public void run() {
try {
ActivityTaskManager.getService().removeTask(taskId);
} catch (RemoteException e) {
Log.w(TAG, "Failed to remove task=" + taskId, e);
}
}
});
try {
getService().removeTask(taskId);
} catch (RemoteException e) {
Log.w(TAG, "Failed to remove task=" + taskId, e);
}
}
/**
* Removes all the recent tasks.
*/
public void removeAllRecentTasks() {
mBackgroundExecutor.submit(new Runnable() {
@Override
public void run() {
try {
ActivityTaskManager.getService().removeAllVisibleRecentTasks();
} catch (RemoteException e) {
Log.w(TAG, "Failed to remove all tasks", e);
}
}
});
}
/**
* Cancels the current window transtion to/from Recents for the given task id.
*/
public void cancelWindowTransition(int taskId) {
try {
ActivityTaskManager.getService().cancelTaskWindowTransition(taskId);
getService().removeAllVisibleRecentTasks();
} catch (RemoteException e) {
Log.w(TAG, "Failed to cancel window transition for task=" + taskId, e);
Log.w(TAG, "Failed to remove all tasks", e);
}
}
@@ -469,7 +310,7 @@ public class ActivityManagerWrapper {
*/
public boolean isScreenPinningActive() {
try {
return ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED;
return getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED;
} catch (RemoteException e) {
return false;
}
@@ -488,7 +329,7 @@ public class ActivityManagerWrapper {
*/
public boolean isLockToAppActive() {
try {
return ActivityTaskManager.getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
return getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
} catch (RemoteException e) {
return false;
}
@@ -499,7 +340,7 @@ public class ActivityManagerWrapper {
*/
public boolean isLockTaskKioskModeActive() {
try {
return ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
return getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
} catch (RemoteException e) {
return false;
}
@@ -16,8 +16,6 @@
package com.android.systemui.shared.system;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -26,6 +24,8 @@ import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
import com.android.systemui.shared.recents.model.Task;
/**
* Wrapper around internal ActivityOptions creation.
*/
@@ -46,9 +46,6 @@ public abstract class ActivityOptionsCompat {
options.setLaunchWindowingMode(isPrimary
? WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
: WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
options.setSplitScreenCreateMode(dockTopLeft
? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
: SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
return options;
}
@@ -63,12 +60,25 @@ public abstract class ActivityOptionsCompat {
public static ActivityOptions makeRemoteAnimation(
RemoteAnimationAdapterCompat remoteAnimationAdapter) {
return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped());
return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped(),
remoteAnimationAdapter.getRemoteTransition().getTransition());
}
/**
* Constructs an ActivityOptions object that will delegate its transition handling to a
* `remoteTransition`.
*/
public static ActivityOptions makeRemoteTransition(RemoteTransitionCompat remoteTransition) {
return ActivityOptions.makeRemoteTransition(remoteTransition.getTransition());
}
/**
* Returns ActivityOptions for overriding task transition animation.
*/
public static ActivityOptions makeCustomAnimation(Context context, int enterResId,
int exitResId, final Runnable callback, final Handler callbackHandler) {
return ActivityOptions.makeCustomAnimation(context, enterResId, exitResId, callbackHandler,
return ActivityOptions.makeCustomTaskAnimation(context, enterResId, exitResId,
callbackHandler,
new ActivityOptions.OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
@@ -86,4 +96,23 @@ public abstract class ActivityOptionsCompat {
opts.setFreezeRecentTasksReordering();
return opts;
}
/**
* Sets the launch event time from launcher.
*/
public static ActivityOptions setLauncherSourceInfo(ActivityOptions opts, long uptimeMillis) {
opts.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER, uptimeMillis);
return opts;
}
/**
* Sets Task specific information to the activity options
*/
public static void addTaskInfo(ActivityOptions opts, Task.TaskKey taskKey) {
if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// We show non-visible docked tasks in Recents, but we always want to launch
// them in the fullscreen stack.
opts.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
}
}
}
@@ -1,61 +0,0 @@
/*
* Copyright (C) 2017 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.shared.system;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Offloads work from other threads by running it in a background thread.
*/
public class BackgroundExecutor {
private static final BackgroundExecutor sInstance = new BackgroundExecutor();
private final ExecutorService mExecutorService = Executors.newFixedThreadPool(2);
/**
* @return the static instance of the background executor.
*/
public static BackgroundExecutor get() {
return sInstance;
}
/**
* Runs the given {@param callable} on one of the background executor threads.
*/
public <T> Future<T> submit(Callable<T> callable) {
return mExecutorService.submit(callable);
}
/**
* Runs the given {@param runnable} on one of the background executor threads.
*/
public Future<?> submit(Runnable runnable) {
return mExecutorService.submit(runnable);
}
/**
* Runs the given {@param runnable} on one of the background executor threads. Return
* {@param result} when the future is resolved.
*/
public <T> Future<T> submit(Runnable runnable, T result) {
return mExecutorService.submit(runnable, result);
}
}
@@ -16,22 +16,20 @@
package com.android.systemui.shared.system;
import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
import android.app.ActivityManager;
import android.os.SystemProperties;
public abstract class BlurUtils {
private static boolean mBlurSupportedSysProp = SystemProperties
.getBoolean("ro.surface_flinger.supports_background_blur", false);
private static boolean mBlurDisabledSysProp = SystemProperties
.getBoolean("persist.sys.sf.disable_blurs", false);
/**
* If this device can render blurs.
*
* @return {@code true} when supported.
*/
public static boolean supportsBlursOnWindows() {
return mBlurSupportedSysProp && !mBlurDisabledSysProp && ActivityManager.isHighEndGfx();
return CROSS_WINDOW_BLUR_SUPPORTED && ActivityManager.isHighEndGfx()
&& !SystemProperties.getBoolean("persist.sysui.disableBlur", false);
}
}
@@ -1,37 +0,0 @@
/*
* Copyright (C) 2017 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.shared.system;
import static android.view.Choreographer.CALLBACK_INPUT;
import android.view.Choreographer;
/**
* Wraps the internal choreographer.
*/
public class ChoreographerCompat {
/**
* Posts an input callback to the choreographer.
*/
public static void postInputFrame(Choreographer choreographer, Runnable runnable) {
choreographer.postCallback(CALLBACK_INPUT, runnable, null);
}
public static Choreographer getSfInstance() {
return Choreographer.getSfInstance();
}
}
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2020 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.shared.system;
import android.content.ClipDescription;
import android.content.Intent;
/**
* Wrapper around ClipDescription.
*/
public abstract class ClipDescriptionCompat {
public static String MIMETYPE_APPLICATION_ACTIVITY =
ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
public static String MIMETYPE_APPLICATION_SHORTCUT =
ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
public static String MIMETYPE_APPLICATION_TASK =
ClipDescription.MIMETYPE_APPLICATION_TASK;
public static String EXTRA_PENDING_INTENT = ClipDescription.EXTRA_PENDING_INTENT;
public static String EXTRA_TASK_ID = Intent.EXTRA_TASK_ID;
}
@@ -14,15 +14,15 @@
* limitations under the License.
*/
package com.android.systemui.shared.recents;
package com.android.systemui.shared.system;
/**
* Listener interface that Launcher attaches to SystemUI to get
* pinned stack animation callbacks.
*/
oneway interface IPinnedStackAnimationListener {
/**
* Notifies the pinned stack animation is started.
*/
void onPinnedStackAnimationStarted();
import android.annotation.UserIdInt;
import android.content.Context;
public class ContextUtils {
/** Get the user associated with this context */
public static @UserIdInt int getUserId(Context context) {
return context.getUserId();
}
}
@@ -16,13 +16,12 @@
package com.android.systemui.shared.system;
import android.os.Bundle;
import android.graphics.Matrix;
import android.os.Looper;
import android.view.BatchedInputEventReceiver;
import android.view.Choreographer;
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventSender;
import android.view.MotionEvent;
/**
@@ -40,16 +39,6 @@ public class InputChannelCompat {
void onInputEvent(InputEvent ev);
}
/**
* Creates a dispatcher from the extras received as part on onInitialize
*/
public static InputEventReceiver fromBundle(Bundle params, String key,
Looper looper, Choreographer choreographer, InputEventListener listener) {
InputChannel channel = params.getParcelable(key);
return new InputEventReceiver(channel, looper, choreographer, listener);
}
/**
* Version of addBatch method which preserves time accuracy in nanoseconds instead of
* converting the time to milliseconds.
@@ -63,17 +52,21 @@ public class InputChannelCompat {
return target.addBatch(src);
}
/** @see MotionEvent#createRotateMatrix */
public static Matrix createRotationMatrix(
/*@Surface.Rotation*/ int rotation, int displayW, int displayH) {
return MotionEvent.createRotateMatrix(rotation, displayW, displayH);
}
/**
* @see BatchedInputEventReceiver
*/
public static class InputEventReceiver {
private final BatchedInputEventReceiver mReceiver;
private final InputChannel mInputChannel;
public InputEventReceiver(InputChannel inputChannel, Looper looper,
Choreographer choreographer, final InputEventListener listener) {
mInputChannel = inputChannel;
mReceiver = new BatchedInputEventReceiver(inputChannel, looper, choreographer) {
@Override
@@ -84,41 +77,18 @@ public class InputChannelCompat {
};
}
/**
* @see BatchedInputEventReceiver#setBatchingEnabled()
*/
public void setBatchingEnabled(boolean batchingEnabled) {
mReceiver.setBatchingEnabled(batchingEnabled);
}
/**
* @see BatchedInputEventReceiver#dispose()
*/
public void dispose() {
mReceiver.dispose();
mInputChannel.dispose();
}
}
/**
* @see InputEventSender
*/
public static class InputEventDispatcher {
private final InputChannel mInputChannel;
private final InputEventSender mSender;
public InputEventDispatcher(InputChannel inputChannel, Looper looper) {
mInputChannel = inputChannel;
mSender = new InputEventSender(inputChannel, looper) { };
}
/**
* @see InputEventSender#sendInputEvent(int, InputEvent)
*/
public void dispatch(InputEvent ev) {
mSender.sendInputEvent(ev.getSequenceNumber(), ev);
}
/**
* @see InputEventSender#dispose()
*/
public void dispose() {
mSender.dispose();
mInputChannel.dispose();
}
}
}
@@ -36,6 +36,7 @@ import java.io.PrintWriter;
/**
* Manages the input consumer that allows the SystemUI to directly receive input.
* TODO: Refactor this for the gesture nav case
*/
public class InputConsumerController {
@@ -98,14 +99,6 @@ public class InputConsumerController {
mName = name;
}
/**
* @return A controller for the pip input consumer.
*/
public static InputConsumerController getPipInputConsumer() {
return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(),
INPUT_CONSUMER_PIP);
}
/**
* @return A controller for the recents animation input consumer.
*/
@@ -155,7 +148,6 @@ public class InputConsumerController {
if (mInputEventReceiver == null) {
final InputChannel inputChannel = new InputChannel();
try {
// TODO(b/113087003): Support Picture-in-picture in multi-display.
mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
} catch (RemoteException e) {
@@ -175,7 +167,6 @@ public class InputConsumerController {
public void unregisterInputConsumer() {
if (mInputEventReceiver != null) {
try {
// TODO(b/113087003): Support Picture-in-picture in multi-display.
mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
} catch (RemoteException e) {
Log.e(TAG, "Failed to destroy input consumer", e);
@@ -15,7 +15,7 @@
*/
package com.android.systemui.shared.system;
import android.os.Bundle;
import android.hardware.input.InputManager;
import android.os.Looper;
import android.view.Choreographer;
import android.view.InputMonitor;
@@ -27,11 +27,13 @@ import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
* @see android.view.InputMonitor
*/
public class InputMonitorCompat {
private final InputMonitor mInputMonitor;
private InputMonitorCompat(InputMonitor monitor) {
mInputMonitor = monitor;
/**
* Monitor input on the specified display for gestures.
*/
public InputMonitorCompat(String name, int displayId) {
mInputMonitor = InputManager.getInstance().monitorGestureInput(name, displayId);
}
/**
@@ -56,11 +58,4 @@ public class InputMonitorCompat {
return new InputEventReceiver(mInputMonitor.getInputChannel(), looper, choreographer,
listener);
}
/**
* Gets the input monitor stored in a bundle
*/
public static InputMonitorCompat fromBundle(Bundle bundle, String key) {
return new InputMonitorCompat((InputMonitor) bundle.getParcelable(key));
}
}
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2020 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.shared.system;
import android.annotation.IntDef;
import android.os.Build;
import android.view.View;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public final class InteractionJankMonitorWrapper {
private static final String TAG = "JankMonitorWrapper";
// Launcher journeys.
public static final int CUJ_APP_LAUNCH_FROM_RECENTS =
InteractionJankMonitor.CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS;
public static final int CUJ_APP_LAUNCH_FROM_ICON =
InteractionJankMonitor.CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON;
public static final int CUJ_APP_CLOSE_TO_HOME =
InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_HOME;
public static final int CUJ_APP_CLOSE_TO_PIP =
InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP;
public static final int CUJ_QUICK_SWITCH =
InteractionJankMonitor.CUJ_LAUNCHER_QUICK_SWITCH;
public static final int CUJ_OPEN_ALL_APPS =
InteractionJankMonitor.CUJ_LAUNCHER_OPEN_ALL_APPS;
public static final int CUJ_ALL_APPS_SCROLL =
InteractionJankMonitor.CUJ_LAUNCHER_ALL_APPS_SCROLL;
public static final int CUJ_APP_LAUNCH_FROM_WIDGET =
InteractionJankMonitor.CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET;
@IntDef({
CUJ_APP_LAUNCH_FROM_RECENTS,
CUJ_APP_LAUNCH_FROM_ICON,
CUJ_APP_CLOSE_TO_HOME,
CUJ_APP_CLOSE_TO_PIP,
CUJ_QUICK_SWITCH,
CUJ_APP_LAUNCH_FROM_WIDGET,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
}
/**
* Begin a trace session.
*
* @param v an attached view.
* @param cujType the specific {@link InteractionJankMonitor.CujType}.
*/
public static void begin(View v, @CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().begin(v, cujType);
}
/**
* Begin a trace session.
*
* @param v an attached view.
* @param cujType the specific {@link InteractionJankMonitor.CujType}.
* @param timeout duration to cancel the instrumentation in ms
*/
public static void begin(View v, @CujType int cujType, long timeout) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
Configuration.Builder builder =
new Configuration.Builder(cujType)
.setView(v)
.setTimeout(timeout);
InteractionJankMonitor.getInstance().begin(builder);
}
/**
* End a trace session.
*
* @param cujType the specific {@link InteractionJankMonitor.CujType}.
*/
public static void end(@CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().end(cujType);
}
/**
* Cancel the trace session.
*/
public static void cancel(@CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().cancel(cujType);
}
}
@@ -24,11 +24,18 @@ import com.android.internal.util.LatencyTracker;
* @see LatencyTracker
*/
public class LatencyTrackerCompat {
public static boolean isEnabled(Context context) {
return LatencyTracker.isEnabled(context);
/**
* @see LatencyTracker
* @deprecated Please use {@link LatencyTrackerCompat#logToggleRecents(Context, int)} instead.
*/
@Deprecated
public static void logToggleRecents(int duration) {
LatencyTracker.logActionDeprecated(LatencyTracker.ACTION_TOGGLE_RECENTS, duration, false);
}
public static void logToggleRecents(int duration) {
LatencyTracker.logAction(LatencyTracker.ACTION_TOGGLE_RECENTS, duration);
/** @see LatencyTracker */
public static void logToggleRecents(Context context, int duration) {
LatencyTracker.getInstance(context).logAction(LatencyTracker.ACTION_TOGGLE_RECENTS,
duration);
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2020 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.shared.system;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.pm.LauncherApps;
import android.os.Bundle;
import android.os.UserHandle;
/**
* Wrapper around LauncherApps.
*/
public abstract class LauncherAppsCompat {
public static PendingIntent getMainActivityLaunchIntent(LauncherApps launcherApps,
ComponentName component, Bundle startActivityOptions, UserHandle user) {
return launcherApps.getMainActivityLaunchIntent(component, startActivityOptions, user);
}
}
@@ -21,9 +21,4 @@ public class LauncherEventUtil {
// Constants for the Action
public static final int VISIBLE = 0;
public static final int DISMISS = 1;
// Constants for the Target (View)
public static final int RECENTS_SWIPE_UP_ONBOARDING_TIP = 0;
public static final int RECENTS_QUICK_SCRUB_ONBOARDING_TIP = 1;
}
@@ -0,0 +1,76 @@
/*
* 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.shared.system;
/**
* These strings are part of the {@link com.android.systemui.people.PeopleProvider} API
* contract. The API returns a People Tile preview that can be displayed by calling packages.
* The provider is part of the SystemUI service, and the strings live here for shared access with
* Launcher (caller).
*/
public class PeopleProviderUtils {
/**
* ContentProvider URI scheme.
* @hide
*/
public static final String PEOPLE_PROVIDER_SCHEME = "content://";
/**
* ContentProvider URI authority.
* @hide
*/
public static final String PEOPLE_PROVIDER_AUTHORITY =
"com.android.systemui.people.PeopleProvider";
/**
* Method name for getting People Tile preview.
* @hide
*/
public static final String GET_PEOPLE_TILE_PREVIEW_METHOD = "get_people_tile_preview";
/**
* Extras bundle key specifying shortcut Id of the People Tile preview requested.
* @hide
*/
public static final String EXTRAS_KEY_SHORTCUT_ID = "shortcut_id";
/**
* Extras bundle key specifying package name of the People Tile preview requested.
* @hide
*/
public static final String EXTRAS_KEY_PACKAGE_NAME = "package_name";
/**
* Extras bundle key specifying {@code UserHandle} of the People Tile preview requested.
* @hide
*/
public static final String EXTRAS_KEY_USER_HANDLE = "user_handle";
/**
* Response bundle key to access the returned People Tile preview.
* @hide
*/
public static final String RESPONSE_KEY_REMOTE_VIEWS = "remote_views";
/**
* Name of the permission needed to get a People Tile preview for a given conversation shortcut.
* @hide
*/
public static final String GET_PEOPLE_TILE_PREVIEW_PERMISSION =
"android.permission.GET_PEOPLE_TILE_PREVIEW";
}
@@ -1,124 +0,0 @@
/*
* Copyright (C) 2019 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.shared.system;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.view.DisplayInfo;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
import java.util.ArrayList;
import java.util.List;
/**
* PinnedStackListener that simply forwards all calls to each listener added via
* {@link #addListener}. This is necessary since calling
* {@link com.android.server.wm.WindowManagerService#registerPinnedStackListener} replaces any
* previously set listener.
*/
public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub {
private List<PinnedStackListener> mListeners = new ArrayList<>();
/** Adds a listener to receive updates from the WindowManagerService. */
public void addListener(PinnedStackListener listener) {
mListeners.add(listener);
}
/** Removes a listener so it will no longer receive updates from the WindowManagerService. */
public void removeListener(PinnedStackListener listener) {
mListeners.remove(listener);
}
@Override
public void onListenerRegistered(IPinnedStackController controller) {
for (PinnedStackListener listener : mListeners) {
listener.onListenerRegistered(controller);
}
}
@Override
public void onMovementBoundsChanged(boolean fromImeAdjustment) {
for (PinnedStackListener listener : mListeners) {
listener.onMovementBoundsChanged(fromImeAdjustment);
}
}
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
for (PinnedStackListener listener : mListeners) {
listener.onImeVisibilityChanged(imeVisible, imeHeight);
}
}
@Override
public void onActionsChanged(ParceledListSlice actions) {
for (PinnedStackListener listener : mListeners) {
listener.onActionsChanged(actions);
}
}
@Override
public void onActivityHidden(ComponentName componentName) {
for (PinnedStackListener listener : mListeners) {
listener.onActivityHidden(componentName);
}
}
@Override
public void onDisplayInfoChanged(DisplayInfo displayInfo) {
for (PinnedStackListener listener : mListeners) {
listener.onDisplayInfoChanged(displayInfo);
}
}
@Override
public void onConfigurationChanged() {
for (PinnedStackListener listener : mListeners) {
listener.onConfigurationChanged();
}
}
@Override
public void onAspectRatioChanged(float aspectRatio) {
for (PinnedStackListener listener : mListeners) {
listener.onAspectRatioChanged(aspectRatio);
}
}
/**
* A counterpart of {@link IPinnedStackListener} with empty implementations.
* Subclasses can ignore those methods they do not intend to take action upon.
*/
public static class PinnedStackListener {
public void onListenerRegistered(IPinnedStackController controller) {}
public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
public void onActionsChanged(ParceledListSlice actions) {}
public void onActivityHidden(ComponentName componentName) {}
public void onDisplayInfoChanged(DisplayInfo displayInfo) {}
public void onConfigurationChanged() {}
public void onAspectRatioChanged(float aspectRatio) {}
}
}
@@ -23,7 +23,6 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.view.ViewConfiguration;
import android.view.WindowManagerPolicyConstants;
@@ -37,11 +36,27 @@ import java.util.StringJoiner;
* Various shared constants between Launcher and SysUI as part of quickstep
*/
public class QuickStepContract {
// Fully qualified name of the Launcher activity.
public static final String LAUNCHER_ACTIVITY_CLASS_NAME =
"com.google.android.apps.nexuslauncher.NexusLauncherActivity";
public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor";
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
// See IPip.aidl
public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
// See ISplitScreen.aidl
public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
// See IOneHanded.aidl
public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed";
// See IShellTransitions.aidl
public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS =
"extra_shell_shell_transitions";
// See IStartingWindow.aidl
public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
"extra_shell_starting_window";
// See ISmartspaceTransitionController.aidl
public static final String KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER = "smartspace_transition";
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
@@ -89,6 +104,14 @@ public class QuickStepContract {
public static final int SYSUI_STATE_BUBBLES_EXPANDED = 1 << 14;
// The global actions dialog is showing
public static final int SYSUI_STATE_GLOBAL_ACTIONS_SHOWING = 1 << 15;
// The one-handed mode is active
public static final int SYSUI_STATE_ONE_HANDED_ACTIVE = 1 << 16;
// Allow system gesture no matter the system bar(s) is visible or not
public static final int SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY = 1 << 17;
// The IME is showing
public static final int SYSUI_STATE_IME_SHOWING = 1 << 18;
// The window magnification is overlapped with system gesture insets at the bottom.
public static final int SYSUI_STATE_MAGNIFICATION_OVERLAP = 1 << 19;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -106,7 +129,11 @@ public class QuickStepContract {
SYSUI_STATE_TRACING_ENABLED,
SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
SYSUI_STATE_BUBBLES_EXPANDED,
SYSUI_STATE_GLOBAL_ACTIONS_SHOWING
SYSUI_STATE_GLOBAL_ACTIONS_SHOWING,
SYSUI_STATE_ONE_HANDED_ACTIVE,
SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
SYSUI_STATE_IME_SHOWING,
SYSUI_STATE_MAGNIFICATION_OVERLAP
})
public @interface SystemUiStateFlags {}
@@ -130,6 +157,11 @@ public class QuickStepContract {
str.add((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0
? "asst_gesture_constrain" : "");
str.add((flags & SYSUI_STATE_BUBBLES_EXPANDED) != 0 ? "bubbles_expanded" : "");
str.add((flags & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0 ? "one_handed_active" : "");
str.add((flags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0
? "allow_gesture" : "");
str.add((flags & SYSUI_STATE_IME_SHOWING) != 0 ? "ime_visible" : "");
str.add((flags & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0 ? "magnification_overlap" : "");
return str.toString();
}
@@ -172,6 +204,9 @@ public class QuickStepContract {
* disabled.
*/
public static boolean isAssistantGestureDisabled(int sysuiStateFlags) {
if ((sysuiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
sysuiStateFlags &= ~SYSUI_STATE_NAV_BAR_HIDDEN;
}
// Disable when in quick settings, screen pinning, immersive, the bouncer is showing,
// or search is disabled
int disableFlags = SYSUI_STATE_SCREEN_PINNING
@@ -202,6 +237,9 @@ public class QuickStepContract {
|| (sysuiStateFlags & SYSUI_STATE_GLOBAL_ACTIONS_SHOWING) != 0) {
return false;
}
if ((sysuiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
sysuiStateFlags &= ~SYSUI_STATE_NAV_BAR_HIDDEN;
}
// Disable when in immersive, or the notifications are interactive
int disableFlags = SYSUI_STATE_NAV_BAR_HIDDEN
| SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
@@ -236,9 +274,6 @@ public class QuickStepContract {
* scaling, this means that we don't have to reload them on config changes.
*/
public static float getWindowCornerRadius(Resources resources) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return 0;
}
return ScreenDecorationsUtils.getWindowCornerRadius(resources);
}
@@ -246,9 +281,6 @@ public class QuickStepContract {
* If live rounded corners are supported on windows.
*/
public static boolean supportsRoundedCornersOnWindows(Resources resources) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return false;
}
return ScreenDecorationsUtils.supportsRoundedCornersOnWindows(resources);
}
}
@@ -16,10 +16,12 @@
package com.android.systemui.shared.system;
import android.app.ActivityManager.TaskSnapshot;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.SurfaceControl;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.TaskSnapshot;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -69,6 +71,24 @@ public class RecentsAnimationControllerCompat {
}
}
/**
* Sets the final surface transaction on a Task. This is used by Launcher to notify the system
* that animating Activity to PiP has completed and the associated task surface should be
* updated accordingly. This should be called before `finish`
* @param taskId Task id of the Activity in PiP mode.
* @param finishTransaction leash operations for the final transform.
* @param overlay the surface control for an overlay being shown above the pip (can be null)
*/
public void setFinishTaskTransaction(int taskId,
PictureInPictureSurfaceTransaction finishTransaction,
SurfaceControl overlay) {
try {
mAnimationController.setFinishTaskTransaction(taskId, finishTransaction, overlay);
} catch (RemoteException e) {
Log.d(TAG, "Failed to set finish task bounds", e);
}
}
/**
* Finish the current recents animation.
* @param toHome Going to home or back to the previous app.
@@ -121,4 +141,26 @@ public class RecentsAnimationControllerCompat {
return false;
}
}
}
/**
* @see IRecentsAnimationController#detachNavigationBarFromApp
*/
public void detachNavigationBarFromApp(boolean moveHomeToTop) {
try {
mAnimationController.detachNavigationBarFromApp(moveHomeToTop);
} catch (RemoteException e) {
Log.e(TAG, "Failed to detach the navigation bar from app", e);
}
}
/**
* @see IRecentsAnimationController#animateNavigationBarToApp(long)
*/
public void animateNavigationBarToApp(long duration) {
try {
mAnimationController.animateNavigationBarToApp(duration);
} catch (RemoteException e) {
Log.e(TAG, "Failed to animate the navigation bar to app", e);
}
}
}
@@ -16,12 +16,30 @@
package com.android.systemui.shared.system;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.TransitionOldType;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import android.annotation.SuppressLint;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.TransitionInfo;
import java.util.ArrayList;
/**
* @see RemoteAnimationAdapter
@@ -29,28 +47,43 @@ import android.view.RemoteAnimationTarget;
public class RemoteAnimationAdapterCompat {
private final RemoteAnimationAdapter mWrapped;
private final RemoteTransitionCompat mRemoteTransition;
public RemoteAnimationAdapterCompat(RemoteAnimationRunnerCompat runner, long duration,
long statusBarTransitionDelay) {
mWrapped = new RemoteAnimationAdapter(wrapRemoteAnimationRunner(runner), duration,
statusBarTransitionDelay);
mRemoteTransition = buildRemoteTransition(runner);
}
RemoteAnimationAdapter getWrapped() {
return mWrapped;
}
/** Helper to just build a remote transition. Use this if the legacy adapter isn't needed. */
public static RemoteTransitionCompat buildRemoteTransition(RemoteAnimationRunnerCompat runner) {
return new RemoteTransitionCompat(wrapRemoteTransition(runner));
}
public RemoteTransitionCompat getRemoteTransition() {
return mRemoteTransition;
}
private static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner(
final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
return new IRemoteAnimationRunner.Stub() {
@Override
public void onAnimationStart(RemoteAnimationTarget[] apps,
public void onAnimationStart(@TransitionOldType int transit,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
final RemoteAnimationTargetCompat[] appsCompat =
RemoteAnimationTargetCompat.wrap(apps);
final RemoteAnimationTargetCompat[] wallpapersCompat =
RemoteAnimationTargetCompat.wrap(wallpapers);
final RemoteAnimationTargetCompat[] nonAppsCompat =
RemoteAnimationTargetCompat.wrap(nonApps);
final Runnable animationFinishedCallback = new Runnable() {
@Override
public void run() {
@@ -62,8 +95,8 @@ public class RemoteAnimationAdapterCompat {
}
}
};
remoteAnimationAdapter.onAnimationStart(appsCompat, wallpapersCompat,
animationFinishedCallback);
remoteAnimationAdapter.onAnimationStart(transit, appsCompat, wallpapersCompat,
nonAppsCompat, animationFinishedCallback);
}
@Override
@@ -72,4 +105,182 @@ public class RemoteAnimationAdapterCompat {
}
};
}
private static class CounterRotator {
SurfaceControl mSurface = null;
ArrayList<SurfaceControl> mRotateChildren = null;
void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta,
float displayW, float displayH) {
if (rotateDelta == 0) return;
mRotateChildren = new ArrayList<>();
// We want to counter-rotate, so subtract from 4
rotateDelta = 4 - (rotateDelta + 4) % 4;
mSurface = new SurfaceControl.Builder()
.setName("Transition Unrotate")
.setContainerLayer()
.setParent(parent)
.build();
// column-major
if (rotateDelta == 1) {
t.setMatrix(mSurface, 0, 1, -1, 0);
t.setPosition(mSurface, displayW, 0);
} else if (rotateDelta == 2) {
t.setMatrix(mSurface, -1, 0, 0, -1);
t.setPosition(mSurface, displayW, displayH);
} else if (rotateDelta == 3) {
t.setMatrix(mSurface, 0, -1, 1, 0);
t.setPosition(mSurface, 0, displayH);
}
t.show(mSurface);
}
void addChild(SurfaceControl.Transaction t, SurfaceControl child) {
if (mSurface == null) return;
t.reparent(child, mSurface);
mRotateChildren.add(child);
}
void cleanUp(SurfaceControl rootLeash) {
if (mSurface == null) return;
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
for (int i = mRotateChildren.size() - 1; i >= 0; --i) {
t.reparent(mRotateChildren.get(i), rootLeash);
}
t.remove(mSurface);
t.apply();
}
}
private static IRemoteTransition.Stub wrapRemoteTransition(
final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
return new IRemoteTransition.Stub() {
@Override
public void startAnimation(IBinder token, TransitionInfo info,
SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishCallback) {
final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>();
final RemoteAnimationTargetCompat[] appsCompat =
RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */, t, leashMap);
final RemoteAnimationTargetCompat[] wallpapersCompat =
RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */, t, leashMap);
// TODO(bc-unlock): Build wrapped object for non-apps target.
final RemoteAnimationTargetCompat[] nonAppsCompat =
new RemoteAnimationTargetCompat[0];
// TODO(b/177438007): Move this set-up logic into launcher's animation impl.
boolean isReturnToHome = false;
TransitionInfo.Change launcherTask = null;
TransitionInfo.Change wallpaper = null;
int launcherLayer = 0;
int rotateDelta = 0;
float displayW = 0;
float displayH = 0;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getTaskInfo() != null
&& change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) {
isReturnToHome = change.getMode() == TRANSIT_OPEN
|| change.getMode() == TRANSIT_TO_FRONT;
launcherTask = change;
launcherLayer = info.getChanges().size() - i;
} else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
wallpaper = change;
}
if (change.getParent() == null && change.getEndRotation() >= 0
&& change.getEndRotation() != change.getStartRotation()) {
rotateDelta = change.getEndRotation() - change.getStartRotation();
displayW = change.getEndAbsBounds().width();
displayH = change.getEndAbsBounds().height();
}
}
// Prepare for rotation if there is one
final CounterRotator counterLauncher = new CounterRotator();
final CounterRotator counterWallpaper = new CounterRotator();
if (launcherTask != null && rotateDelta != 0 && launcherTask.getParent() != null) {
counterLauncher.setup(t, info.getChange(launcherTask.getParent()).getLeash(),
rotateDelta, displayW, displayH);
if (counterLauncher.mSurface != null) {
t.setLayer(counterLauncher.mSurface, launcherLayer);
}
}
if (isReturnToHome) {
if (counterLauncher.mSurface != null) {
t.setLayer(counterLauncher.mSurface, info.getChanges().size() * 3);
}
// Need to "boost" the closing things since that's what launcher expects.
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
final SurfaceControl leash = leashMap.get(change.getLeash());
final int mode = info.getChanges().get(i).getMode();
// Only deal with independent layers
if (!TransitionInfo.isIndependent(change, info)) continue;
if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
t.setLayer(leash, info.getChanges().size() * 3 - i);
counterLauncher.addChild(t, leash);
}
}
// Make wallpaper visible immediately since launcher apparently won't do this.
for (int i = wallpapersCompat.length - 1; i >= 0; --i) {
t.show(wallpapersCompat[i].leash.getSurfaceControl());
t.setAlpha(wallpapersCompat[i].leash.getSurfaceControl(), 1.f);
}
} else {
if (launcherTask != null) {
counterLauncher.addChild(t, leashMap.get(launcherTask.getLeash()));
}
if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) {
counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(),
rotateDelta, displayW, displayH);
if (counterWallpaper.mSurface != null) {
t.setLayer(counterWallpaper.mSurface, -1);
counterWallpaper.addChild(t, leashMap.get(wallpaper.getLeash()));
}
}
}
t.apply();
final Runnable animationFinishedCallback = new Runnable() {
@Override
@SuppressLint("NewApi")
public void run() {
try {
counterLauncher.cleanUp(info.getRootLeash());
counterWallpaper.cleanUp(info.getRootLeash());
// Release surface references now. This is apparently to free GPU
// memory while doing quick operations (eg. during CTS).
for (int i = 0; i < info.getChanges().size(); ++i) {
info.getChanges().get(i).getLeash().release();
}
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
for (int i = 0; i < leashMap.size(); ++i) {
if (leashMap.keyAt(i) == leashMap.valueAt(i)) continue;
t.remove(leashMap.valueAt(i));
}
t.apply();
finishCallback.onTransitionFinished(null /* wct */);
} catch (RemoteException e) {
Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
+ " finished callback", e);
}
}
};
// TODO(bc-unlcok): Pass correct transit type.
remoteAnimationAdapter.onAnimationStart(
TRANSIT_OLD_NONE,
appsCompat, wallpapersCompat, nonAppsCompat,
animationFinishedCallback);
}
@Override
public void mergeAnimation(IBinder token, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget,
IRemoteTransitionFinishedCallback finishCallback) {
// TODO: hook up merge to recents onTaskAppeared if applicable. Until then, ignore
// any incoming merges.
}
};
}
}
@@ -16,8 +16,11 @@
package com.android.systemui.shared.system;
import android.view.WindowManager;
public interface RemoteAnimationRunnerCompat {
void onAnimationStart(RemoteAnimationTargetCompat[] apps,
RemoteAnimationTargetCompat[] wallpapers, Runnable finishedCallback);
void onAnimationStart(@WindowManager.TransitionOldType int transit,
RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers,
RemoteAnimationTargetCompat[] nonApps, Runnable finishedCallback);
void onAnimationCancelled();
}
@@ -16,11 +16,28 @@
package com.android.systemui.shared.system;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
import java.util.ArrayList;
/**
* @see RemoteAnimationTarget
@@ -29,6 +46,7 @@ public class RemoteAnimationTargetCompat {
public static final int MODE_OPENING = RemoteAnimationTarget.MODE_OPENING;
public static final int MODE_CLOSING = RemoteAnimationTarget.MODE_CLOSING;
public static final int MODE_CHANGING = RemoteAnimationTarget.MODE_CHANGING;
public final int mode;
public static final int ACTIVITY_TYPE_UNDEFINED = WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -49,6 +67,9 @@ public class RemoteAnimationTargetCompat {
public final Rect screenSpaceBounds;
public final boolean isNotInRecents;
public final Rect contentInsets;
public final ActivityManager.RunningTaskInfo taskInfo;
public final int rotationChange;
public final int windowType;
private final SurfaceControl mStartLeash;
@@ -66,19 +87,171 @@ public class RemoteAnimationTargetCompat {
isNotInRecents = app.isNotInRecents;
contentInsets = app.contentInsets;
activityType = app.windowConfiguration.getActivityType();
taskInfo = app.taskInfo;
rotationChange = 0;
mStartLeash = app.startLeash;
windowType = app.windowType;
}
private static int newModeToLegacyMode(int newMode) {
switch (newMode) {
case WindowManager.TRANSIT_OPEN:
case WindowManager.TRANSIT_TO_FRONT:
return MODE_OPENING;
case WindowManager.TRANSIT_CLOSE:
case WindowManager.TRANSIT_TO_BACK:
return MODE_CLOSING;
default:
return 2; // MODE_CHANGING
}
}
/**
* Almost a copy of Transitions#setupStartState.
* TODO: remove when there is proper cross-process transaction sync.
*/
@SuppressLint("NewApi")
private static void setupLeash(@NonNull SurfaceControl leash,
@NonNull TransitionInfo.Change change, int layer,
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
boolean isOpening = info.getType() == TRANSIT_OPEN || info.getType() == TRANSIT_TO_FRONT;
// Put animating stuff above this line and put static stuff below it.
int zSplitLine = info.getChanges().size();
// changes should be ordered top-to-bottom in z
final int mode = change.getMode();
// Don't move anything that isn't independent within its parents
if (!TransitionInfo.isIndependent(change, info)) {
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
t.show(leash);
t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
}
return;
}
boolean hasParent = change.getParent() != null;
if (!hasParent) {
t.reparent(leash, info.getRootLeash());
t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
change.getStartAbsBounds().top - info.getRootOffset().y);
}
t.show(leash);
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
if (isOpening) {
t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) {
// if transferred, it should be left visible.
t.setAlpha(leash, 0.f);
}
} else {
// put on bottom and leave it visible
t.setLayer(leash, zSplitLine - layer);
}
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
if (isOpening) {
// put on bottom and leave visible
t.setLayer(leash, zSplitLine - layer);
} else {
// put on top
t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
}
} else { // CHANGE
t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
}
}
@SuppressLint("NewApi")
private static SurfaceControl createLeash(TransitionInfo info, TransitionInfo.Change change,
int order, SurfaceControl.Transaction t) {
// TODO: once we can properly sync transactions across process, then get rid of this leash.
if (change.getParent() != null && (change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
// Special case for wallpaper atm. Normally these are left alone; but, a quirk of
// making leashes means we have to handle them specially.
return change.getLeash();
}
SurfaceControl leashSurface = new SurfaceControl.Builder()
.setName(change.getLeash().toString() + "_transition-leash")
.setContainerLayer().setParent(change.getParent() == null ? info.getRootLeash()
: info.getChange(change.getParent()).getLeash()).build();
// Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
t.reparent(change.getLeash(), leashSurface);
t.setAlpha(change.getLeash(), 1.0f);
t.show(change.getLeash());
t.setPosition(change.getLeash(), 0, 0);
t.setLayer(change.getLeash(), 0);
return leashSurface;
}
public RemoteAnimationTargetCompat(TransitionInfo.Change change, int order,
TransitionInfo info, SurfaceControl.Transaction t) {
taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;
mode = newModeToLegacyMode(change.getMode());
// TODO: once we can properly sync transactions across process, then get rid of this leash.
leash = new SurfaceControlCompat(createLeash(info, change, order, t));
isTranslucent = (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0
|| (change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0;
clipRect = null;
position = null;
localBounds = new Rect(change.getEndAbsBounds());
localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
sourceContainerBounds = null;
screenSpaceBounds = new Rect(change.getEndAbsBounds());
prefixOrderIndex = order;
// TODO(shell-transitions): I guess we need to send content insets? evaluate how its used.
contentInsets = new Rect(0, 0, 0, 0);
if (change.getTaskInfo() != null) {
isNotInRecents = !change.getTaskInfo().isRunning;
activityType = change.getTaskInfo().getActivityType();
} else {
isNotInRecents = true;
activityType = ACTIVITY_TYPE_UNDEFINED;
}
taskInfo = change.getTaskInfo();
mStartLeash = null;
rotationChange = change.getEndRotation() - change.getStartRotation();
windowType = INVALID_WINDOW_TYPE;
}
public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
final RemoteAnimationTargetCompat[] appsCompat =
new RemoteAnimationTargetCompat[apps != null ? apps.length : 0];
for (int i = 0; i < apps.length; i++) {
final int length = apps != null ? apps.length : 0;
final RemoteAnimationTargetCompat[] appsCompat = new RemoteAnimationTargetCompat[length];
for (int i = 0; i < length; i++) {
appsCompat[i] = new RemoteAnimationTargetCompat(apps[i]);
}
return appsCompat;
}
/**
* Represents a TransitionInfo object as an array of old-style targets
*
* @param wallpapers If true, this will return wallpaper targets; otherwise it returns
* non-wallpaper targets.
* @param leashMap Temporary map of change leash -> launcher leash. Is an output, so should be
* populated by this function. If null, it is ignored.
*/
public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers,
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
for (int i = 0; i < info.getChanges().size(); i++) {
boolean changeIsWallpaper =
(info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
if (wallpapers != changeIsWallpaper) continue;
out.add(new RemoteAnimationTargetCompat(info.getChanges().get(i),
info.getChanges().size() - i, info, t));
if (leashMap == null) continue;
leashMap.put(info.getChanges().get(i).getLeash(),
out.get(out.size() - 1).leash.mSurfaceControl);
}
return out.toArray(new RemoteAnimationTargetCompat[out.size()]);
}
/**
* @see SurfaceControl#release()
*/
@@ -88,4 +261,4 @@ public class RemoteAnimationTargetCompat {
mStartLeash.release();
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 The Android Open Source Project
* Copyright (C) 2020 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.
@@ -16,19 +16,4 @@
package com.android.systemui.shared.system;
import android.content.Context;
/**
* Wraps a context to expose some methods for launcher to call.
*/
public class ContextCompat {
private final Context mWrapped;
public ContextCompat(Context context) {
mWrapped = context;
}
public int getUserId() {
return mWrapped.getUserId();
}
}
parcelable RemoteTransitionCompat;
@@ -0,0 +1,465 @@
/*
* Copyright (C) 2020 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.shared.system;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DataClass;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.concurrent.Executor;
/**
* Wrapper to expose RemoteTransition (shell transitions) to Launcher.
*
* @see IRemoteTransition
* @see TransitionFilter
*/
@DataClass
public class RemoteTransitionCompat implements Parcelable {
private static final String TAG = "RemoteTransitionCompat";
@NonNull final IRemoteTransition mTransition;
@Nullable TransitionFilter mFilter = null;
RemoteTransitionCompat(IRemoteTransition transition) {
mTransition = transition;
}
public RemoteTransitionCompat(@NonNull RemoteTransitionRunner runner,
@NonNull Executor executor) {
mTransition = new IRemoteTransition.Stub() {
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishedCallback) {
final Runnable finishAdapter = () -> {
try {
finishedCallback.onTransitionFinished(null /* wct */);
} catch (RemoteException e) {
Log.e(TAG, "Failed to call transition finished callback", e);
}
};
executor.execute(() -> runner.startAnimation(transition, info, t, finishAdapter));
}
@Override
public void mergeAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget,
IRemoteTransitionFinishedCallback finishedCallback) {
final Runnable finishAdapter = () -> {
try {
finishedCallback.onTransitionFinished(null /* wct */);
} catch (RemoteException e) {
Log.e(TAG, "Failed to call transition finished callback", e);
}
};
executor.execute(() -> runner.mergeAnimation(transition, info, t, mergeTarget,
finishAdapter));
}
};
}
/** Constructor specifically for recents animation */
public RemoteTransitionCompat(RecentsAnimationListener recents,
RecentsAnimationControllerCompat controller) {
mTransition = new IRemoteTransition.Stub() {
final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap();
IBinder mToken = null;
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishedCallback) {
final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>();
final RemoteAnimationTargetCompat[] apps =
RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */, t, leashMap);
final RemoteAnimationTargetCompat[] wallpapers =
RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */, t, leashMap);
// TODO(b/177438007): Move this set-up logic into launcher's animation impl.
mToken = transition;
// This transition is for opening recents, so recents is on-top. We want to draw
// the current going-away task on top of recents, though, so move it to front
WindowContainerToken pausingTask = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) {
t.setLayer(leashMap.get(change.getLeash()),
info.getChanges().size() * 3 - i);
if (change.getTaskInfo() != null) {
pausingTask = change.getTaskInfo().token;
}
}
}
// Also make all the wallpapers opaque since we want the visible from the start
for (int i = wallpapers.length - 1; i >= 0; --i) {
t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1);
}
t.apply();
mRecentsSession.setup(controller, info, finishedCallback, pausingTask,
leashMap);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
}
@Override
public void mergeAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget,
IRemoteTransitionFinishedCallback finishedCallback) {
if (!mergeTarget.equals(mToken)) return;
if (!mRecentsSession.merge(info, t, recents)) return;
try {
finishedCallback.onTransitionFinished(null /* wct */);
} catch (RemoteException e) {
Log.e(TAG, "Error merging transition.", e);
}
}
};
}
/** Adds a filter check that restricts this remote transition to home open transitions. */
public void addHomeOpenCheck() {
if (mFilter == null) {
mFilter = new TransitionFilter();
}
mFilter.mRequirements =
new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
mFilter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME;
mFilter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
}
/**
* Wrapper to hook up parts of recents animation to shell transition.
* TODO(b/177438007): Remove this once Launcher handles shell transitions directly.
*/
@VisibleForTesting
static class RecentsControllerWrap extends RecentsAnimationControllerCompat {
private RecentsAnimationControllerCompat mWrapped = null;
private IRemoteTransitionFinishedCallback mFinishCB = null;
private WindowContainerToken mPausingTask = null;
private TransitionInfo mInfo = null;
private SurfaceControl mOpeningLeash = null;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask,
ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active.");
}
mWrapped = wrapped;
mInfo = info;
mFinishCB = finishCB;
mPausingTask = pausingTask;
mLeashMap = leashMap;
}
@SuppressLint("NewApi")
boolean merge(TransitionInfo info, SurfaceControl.Transaction t,
RecentsAnimationListener recents) {
TransitionInfo.Change openingTask = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
if (change.getTaskInfo() != null) {
if (openingTask != null) {
Log.w(TAG, " Expecting to merge a task-open, but got >1 opening "
+ "tasks");
}
openingTask = change;
}
}
}
if (openingTask == null) return false;
mOpeningLeash = openingTask.getLeash();
if (openingTask.getContainer().equals(mPausingTask)) {
// In this case, we are "returning" to the already running app, so just consume
// the merge and do nothing.
return true;
}
// We are receiving a new opening task, so convert to onTaskAppeared.
final int layer = mInfo.getChanges().size() * 3;
final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat(
openingTask, layer, mInfo, t);
mLeashMap.put(mOpeningLeash, target.leash.mSurfaceControl);
t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash());
t.setLayer(target.leash.mSurfaceControl, layer);
t.hide(target.leash.mSurfaceControl);
t.apply();
recents.onTaskAppeared(target);
return true;
}
@Override public ThumbnailData screenshotTask(int taskId) {
return mWrapped != null ? mWrapped.screenshotTask(taskId) : null;
}
@Override public void setInputConsumerEnabled(boolean enabled) {
if (mWrapped != null) mWrapped.setInputConsumerEnabled(enabled);
}
@Override public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) {
if (mWrapped != null) mWrapped.setAnimationTargetsBehindSystemBars(behindSystemBars);
}
@Override public void hideCurrentInputMethod() {
mWrapped.hideCurrentInputMethod();
}
@Override public void setFinishTaskTransaction(int taskId,
PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) {
if (mWrapped != null) {
mWrapped.setFinishTaskTransaction(taskId, finishTransaction, overlay);
}
}
@Override
@SuppressLint("NewApi")
public void finish(boolean toHome, boolean sendUserLeaveHint) {
if (mFinishCB == null) {
Log.e(TAG, "Duplicate call to finish", new RuntimeException());
return;
}
if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint);
try {
if (!toHome && mPausingTask != null && mOpeningLeash == null) {
// The gesture went back to opening the app rather than continuing with
// recents, so end the transition by moving the app back to the top.
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.reorder(mPausingTask, true /* onTop */);
mFinishCB.onTransitionFinished(wct);
} else {
if (mOpeningLeash != null) {
// TODO: the launcher animation should handle this
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.show(mOpeningLeash);
t.setAlpha(mOpeningLeash, 1.f);
t.apply();
}
mFinishCB.onTransitionFinished(null /* wct */);
}
} catch (RemoteException e) {
Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
}
// Release surface references now. This is apparently to free GPU
// memory while doing quick operations (eg. during CTS).
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
for (int i = 0; i < mLeashMap.size(); ++i) {
if (mLeashMap.keyAt(i) == mLeashMap.valueAt(i)) continue;
t.remove(mLeashMap.valueAt(i));
}
t.apply();
for (int i = 0; i < mInfo.getChanges().size(); ++i) {
mInfo.getChanges().get(i).getLeash().release();
}
// Reset all members.
mWrapped = null;
mFinishCB = null;
mPausingTask = null;
mInfo = null;
mOpeningLeash = null;
mLeashMap = null;
}
@Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
if (mWrapped != null) mWrapped.setDeferCancelUntilNextTransition(defer, screenshot);
}
@Override public void cleanupScreenshot() {
if (mWrapped != null) mWrapped.cleanupScreenshot();
}
@Override public void setWillFinishToHome(boolean willFinishToHome) {
if (mWrapped != null) mWrapped.setWillFinishToHome(willFinishToHome);
}
/**
* @see IRecentsAnimationController#removeTask
*/
@Override public boolean removeTask(int taskId) {
return mWrapped != null ? mWrapped.removeTask(taskId) : false;
}
}
// Code below generated by codegen v1.0.21.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
@DataClass.Generated.Member
public @NonNull IRemoteTransition getTransition() {
return mTransition;
}
@DataClass.Generated.Member
public @Nullable TransitionFilter getFilter() {
return mFilter;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
if (mFilter != null) flg |= 0x2;
dest.writeByte(flg);
dest.writeStrongInterface(mTransition);
if (mFilter != null) dest.writeTypedObject(mFilter, flags);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
protected RemoteTransitionCompat(@NonNull android.os.Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
IRemoteTransition transition = IRemoteTransition.Stub.asInterface(in.readStrongBinder());
TransitionFilter filter = (flg & 0x2) == 0 ? null : (TransitionFilter) in.readTypedObject(TransitionFilter.CREATOR);
this.mTransition = transition;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mTransition);
this.mFilter = filter;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<RemoteTransitionCompat> CREATOR
= new Parcelable.Creator<RemoteTransitionCompat>() {
@Override
public RemoteTransitionCompat[] newArray(int size) {
return new RemoteTransitionCompat[size];
}
@Override
public RemoteTransitionCompat createFromParcel(@NonNull android.os.Parcel in) {
return new RemoteTransitionCompat(in);
}
};
/**
* A builder for {@link RemoteTransitionCompat}
*/
@SuppressWarnings("WeakerAccess")
@DataClass.Generated.Member
public static class Builder {
private @NonNull IRemoteTransition mTransition;
private @Nullable TransitionFilter mFilter;
private long mBuilderFieldsSet = 0L;
public Builder(
@NonNull IRemoteTransition transition) {
mTransition = transition;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mTransition);
}
@DataClass.Generated.Member
public @NonNull Builder setTransition(@NonNull IRemoteTransition value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
mTransition = value;
return this;
}
@DataClass.Generated.Member
public @NonNull Builder setFilter(@NonNull TransitionFilter value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mFilter = value;
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull RemoteTransitionCompat build() {
checkNotUsed();
mBuilderFieldsSet |= 0x4; // Mark builder used
if ((mBuilderFieldsSet & 0x2) == 0) {
mFilter = null;
}
RemoteTransitionCompat o = new RemoteTransitionCompat(mTransition);
o.mFilter = this.mFilter;
return o;
}
private void checkNotUsed() {
if ((mBuilderFieldsSet & 0x4) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
}
}
@DataClass.Generated(
time = 1606862689344L,
codegenVersion = "1.0.21",
sourceFile = "frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java",
inputSignatures = "final @android.annotation.NonNull com.android.systemui.shared.system.IRemoteTransition mTransition\n @android.annotation.Nullable android.window.TransitionFilter mFilter\npublic void addHomeOpenCheck()\nclass RemoteTransitionCompat extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
@Deprecated
private void __metadata() {}
//@formatter:on
// End of generated code
}
@@ -0,0 +1,42 @@
/*
* 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.shared.system;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
/** Interface for something that runs a remote transition animation. */
public interface RemoteTransitionRunner {
/**
* Starts a transition animation. Once complete, the implementation should call
* `finishCallback`.
*/
void startAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
Runnable finishCallback);
/**
* Attempts to merge a transition into the currently-running animation. If merge is not
* possible/supported, this should do nothing. Otherwise, the implementation should call
* `finishCallback` immediately to indicate that it merged the transition.
*
* @param transition The transition that wants to be merged into the running animation.
* @param mergeTarget The transition to merge into (that this runner is currently animating).
*/
default void mergeAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget, Runnable finishCallback) { }
}
@@ -47,6 +47,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
public static final int FLAG_VISIBILITY = 1 << 6;
public static final int FLAG_RELATIVE_LAYER = 1 << 7;
public static final int FLAG_SHADOW_RADIUS = 1 << 8;
private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
@@ -64,7 +65,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
public SyncRtSurfaceTransactionApplierCompat(View targetView) {
mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
mBarrierSurfaceControl = mTargetViewRootImpl != null
? mTargetViewRootImpl.getRenderSurfaceControl() : null;
? mTargetViewRootImpl.getSurfaceControl() : null;
mApplyHandler = new Handler(new Callback() {
@Override
@@ -113,10 +114,13 @@ public class SyncRtSurfaceTransactionApplierCompat {
for (int i = params.length - 1; i >= 0; i--) {
SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
params[i];
t.deferTransactionUntil(surfaceParams.surface, mBarrierSurfaceControl, frame);
surfaceParams.applyTo(t);
}
t.apply();
if (mTargetViewRootImpl != null) {
mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
} else {
t.apply();
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
.sendToTarget();
@@ -196,6 +200,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
SurfaceControl relativeTo;
int relativeLayer;
boolean visible;
float shadowRadius;
/**
* @param surface The surface to modify.
@@ -226,7 +231,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
* @return this Builder
*/
public Builder withMatrix(Matrix matrix) {
this.matrix = matrix;
this.matrix = new Matrix(matrix);
flags |= FLAG_MATRIX;
return this;
}
@@ -236,7 +241,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
* @return this Builder
*/
public Builder withWindowCrop(Rect windowCrop) {
this.windowCrop = windowCrop;
this.windowCrop = new Rect(windowCrop);
flags |= FLAG_WINDOW_CROP;
return this;
}
@@ -273,6 +278,16 @@ public class SyncRtSurfaceTransactionApplierCompat {
return this;
}
/**
* @param radius the Radius for the shadows to apply to the surface.
* @return this Builder
*/
public Builder withShadowRadius(float radius) {
this.shadowRadius = radius;
flags |= FLAG_SHADOW_RADIUS;
return this;
}
/**
* @param radius the Radius for blur to apply to the background surfaces.
* @return this Builder
@@ -298,42 +313,26 @@ public class SyncRtSurfaceTransactionApplierCompat {
*/
public SurfaceParams build() {
return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible);
relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible,
shadowRadius);
}
}
/**
* Constructs surface parameters to be applied when the current view state gets pushed to
* RenderThread.
*
* @param surface The surface to modify.
* @param alpha Alpha to apply.
* @param matrix Matrix to apply.
* @param windowCrop Crop to apply, only applied if not {@code null}
*/
public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix,
Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer,
float cornerRadius) {
this(surface.mSurfaceControl,
FLAG_ALL & ~(FLAG_VISIBILITY | FLAG_BACKGROUND_BLUR_RADIUS), alpha,
matrix, windowCrop, layer, relativeTo, relativeLayer, cornerRadius,
0 /* backgroundBlurRadius */, true);
}
private SurfaceParams(SurfaceControl surface, int flags, float alpha, Matrix matrix,
Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer,
float cornerRadius, int backgroundBlurRadius, boolean visible) {
float cornerRadius, int backgroundBlurRadius, boolean visible, float shadowRadius) {
this.flags = flags;
this.surface = surface;
this.alpha = alpha;
this.matrix = new Matrix(matrix);
this.windowCrop = windowCrop != null ? new Rect(windowCrop) : null;
this.matrix = matrix;
this.windowCrop = windowCrop;
this.layer = layer;
this.relativeTo = relativeTo;
this.relativeLayer = relativeLayer;
this.cornerRadius = cornerRadius;
this.backgroundBlurRadius = backgroundBlurRadius;
this.visible = visible;
this.shadowRadius = shadowRadius;
}
private final int flags;
@@ -349,6 +348,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
public final SurfaceControl relativeTo;
public final int relativeLayer;
public final boolean visible;
public final float shadowRadius;
public void applyTo(SurfaceControl.Transaction t) {
if ((flags & FLAG_MATRIX) != 0) {
@@ -379,6 +379,9 @@ public class SyncRtSurfaceTransactionApplierCompat {
if ((flags & FLAG_RELATIVE_LAYER) != 0) {
t.setRelativeLayer(surface, relativeTo, relativeLayer);
}
if ((flags & FLAG_SHADOW_RADIUS) != 0) {
t.setShadowRadius(surface, shadowRadius);
}
}
}
}
@@ -1,48 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.shared.system;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.content.ComponentName;
public class TaskInfoCompat {
public static int getUserId(TaskInfo info) {
return info.userId;
}
public static int getActivityType(TaskInfo info) {
return info.configuration.windowConfiguration.getActivityType();
}
public static int getWindowingMode(TaskInfo info) {
return info.configuration.windowConfiguration.getWindowingMode();
}
public static boolean supportsSplitScreenMultiWindow(TaskInfo info) {
return info.supportsSplitScreenMultiWindow;
}
public static ComponentName getTopActivity(TaskInfo info) {
return info.topActivity;
}
public static ActivityManager.TaskDescription getTaskDescription(TaskInfo info) {
return info.taskDescription;
}
}
@@ -19,7 +19,6 @@ package com.android.systemui.shared.system;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ITaskStackListener;
import android.content.ComponentName;
import android.os.IBinder;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -62,21 +61,6 @@ public abstract class TaskStackChangeListener {
onActivityLaunchOnSecondaryDisplayRerouted();
}
/**
* Called when contents are drawn for the first time on a display which can only contain one
* task.
*
* @param displayId the id of the display on which contents are drawn.
*/
public void onSingleTaskDisplayDrawn(int displayId) { }
/**
* Called when the last task is removed from a display which can only contain one task.
*
* @param displayId the id of the display from which the window is removed.
*/
public void onSingleTaskDisplayEmpty(int displayId) {}
public void onTaskProfileLocked(int taskId, int userId) { }
public void onTaskCreated(int taskId, ComponentName componentName) { }
public void onTaskRemoved(int taskId) { }
@@ -95,7 +79,6 @@ public abstract class TaskStackChangeListener {
public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { }
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) { }
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { }
@@ -117,4 +100,10 @@ public abstract class TaskStackChangeListener {
/** @see ITaskStackListener#onActivityRotation(int)*/
public void onActivityRotation(int displayId) { }
/**
* Called when the lock task mode changes. See ActivityManager#LOCK_TASK_MODE_* and
* LockTaskController.
*/
public void onLockTaskModeChanged(int mode) { }
}
@@ -17,18 +17,15 @@
package com.android.systemui.shared.system;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.app.TaskStackListener;
import android.content.ComponentName;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
import android.window.TaskSnapshot;
import com.android.internal.os.SomeArgs;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -39,211 +36,43 @@ import java.util.List;
/**
* Tracks all the task stack listeners
*/
public class TaskStackChangeListeners extends TaskStackListener {
public class TaskStackChangeListeners {
private static final String TAG = TaskStackChangeListeners.class.getSimpleName();
private static final TaskStackChangeListeners INSTANCE = new TaskStackChangeListeners();
private final Impl mImpl;
private TaskStackChangeListeners() {
mImpl = new Impl(Looper.getMainLooper());
}
public static TaskStackChangeListeners getInstance() {
return INSTANCE;
}
/**
* List of {@link TaskStackChangeListener} registered from {@link #addListener}.
* Registers a task stack listener with the system.
* This should be called on the main thread.
*/
private final List<TaskStackChangeListener> mTaskStackListeners = new ArrayList<>();
private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>();
private final Handler mHandler;
private boolean mRegistered;
public TaskStackChangeListeners(Looper looper) {
mHandler = new H(looper);
}
public void addListener(IActivityManager am, TaskStackChangeListener listener) {
synchronized (mTaskStackListeners) {
mTaskStackListeners.add(listener);
}
if (!mRegistered) {
// Register mTaskStackListener to IActivityManager only once if needed.
try {
ActivityTaskManager.getService().registerTaskStackListener(this);
mRegistered = true;
} catch (Exception e) {
Log.w(TAG, "Failed to call registerTaskStackListener", e);
}
public void registerTaskStackListener(TaskStackChangeListener listener) {
synchronized (mImpl) {
mImpl.addListener(listener);
}
}
public void removeListener(TaskStackChangeListener listener) {
boolean isEmpty;
synchronized (mTaskStackListeners) {
mTaskStackListeners.remove(listener);
isEmpty = mTaskStackListeners.isEmpty();
}
if (isEmpty && mRegistered) {
// Unregister mTaskStackListener once we have no more listeners
try {
ActivityTaskManager.getService().unregisterTaskStackListener(this);
mRegistered = false;
} catch (Exception e) {
Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
}
/**
* Unregisters a task stack listener with the system.
* This should be called on the main thread.
*/
public void unregisterTaskStackListener(TaskStackChangeListener listener) {
synchronized (mImpl) {
mImpl.removeListener(listener);
}
}
@Override
public void onTaskStackChanged() throws RemoteException {
// Call the task changed callback for the non-ui thread listeners first. Copy to a set of
// temp listeners so that we don't lock on mTaskStackListeners while calling all the
// callbacks. This call is always on the same binder thread, so we can just synchronize
// on the copying of the listener list.
synchronized (mTaskStackListeners) {
mTmpListeners.addAll(mTaskStackListeners);
}
for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
mTmpListeners.get(i).onTaskStackChangedBackground();
}
mTmpListeners.clear();
private static class Impl extends TaskStackListener implements Handler.Callback {
mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
}
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId)
throws RemoteException {
mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
mHandler.obtainMessage(H.ON_ACTIVITY_PINNED,
new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget();
}
@Override
public void onActivityUnpinned() throws RemoteException {
mHandler.removeMessages(H.ON_ACTIVITY_UNPINNED);
mHandler.sendEmptyMessage(H.ON_ACTIVITY_UNPINNED);
}
@Override
public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
boolean clearedTask, boolean wasVisible) throws RemoteException {
final SomeArgs args = SomeArgs.obtain();
args.arg1 = task;
args.argi1 = homeTaskVisible ? 1 : 0;
args.argi2 = clearedTask ? 1 : 0;
args.argi3 = wasVisible ? 1 : 0;
mHandler.removeMessages(H.ON_ACTIVITY_RESTART_ATTEMPT);
mHandler.obtainMessage(H.ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
}
@Override
public void onActivityForcedResizable(String packageName, int taskId, int reason)
throws RemoteException {
mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
.sendToTarget();
}
@Override
public void onActivityDismissingDockedStack() throws RemoteException {
mHandler.sendEmptyMessage(H.ON_ACTIVITY_DISMISSING_DOCKED_STACK);
}
@Override
public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
int requestedDisplayId) throws RemoteException {
mHandler.obtainMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED, requestedDisplayId,
0 /* unused */,
taskInfo).sendToTarget();
}
@Override
public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
int requestedDisplayId) throws RemoteException {
mHandler.obtainMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
}
@Override
public void onTaskProfileLocked(int taskId, int userId) throws RemoteException {
mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
}
@Override
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException {
mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
}
@Override
public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
mHandler.obtainMessage(H.ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
}
@Override
public void onTaskRemoved(int taskId) throws RemoteException {
mHandler.obtainMessage(H.ON_TASK_REMOVED, taskId, 0).sendToTarget();
}
@Override
public void onTaskMovedToFront(RunningTaskInfo taskInfo)
throws RemoteException {
mHandler.obtainMessage(H.ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
}
@Override
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) throws RemoteException {
mHandler.obtainMessage(H.ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
}
@Override
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation)
throws RemoteException {
mHandler.obtainMessage(H.ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
requestedOrientation).sendToTarget();
}
@Override
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken)
throws RemoteException {
mHandler.obtainMessage(H.ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId, 0 /* unused */,
activityToken).sendToTarget();
}
@Override
public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
mHandler.obtainMessage(H.ON_SINGLE_TASK_DISPLAY_DRAWN, displayId,
0 /* unused */).sendToTarget();
}
@Override
public void onSingleTaskDisplayEmpty(int displayId) throws RemoteException {
mHandler.obtainMessage(H.ON_SINGLE_TASK_DISPLAY_EMPTY, displayId,
0 /* unused */).sendToTarget();
}
@Override
public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
mHandler.obtainMessage(H.ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
}
@Override
public void onRecentTaskListUpdated() throws RemoteException {
mHandler.obtainMessage(H.ON_TASK_LIST_UPDATED).sendToTarget();
}
@Override
public void onRecentTaskListFrozenChanged(boolean frozen) {
mHandler.obtainMessage(H.ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
.sendToTarget();
}
@Override
public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) {
mHandler.obtainMessage(H.ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
}
@Override
public void onActivityRotation(int displayId) {
mHandler.obtainMessage(H.ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
.sendToTarget();
}
private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
private static final int ON_ACTIVITY_PINNED = 3;
@@ -258,23 +87,199 @@ public class TaskStackChangeListeners extends TaskStackListener {
private static final int ON_TASK_MOVED_TO_FRONT = 14;
private static final int ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE = 15;
private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED = 16;
private static final int ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED = 17;
private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 18;
private static final int ON_SINGLE_TASK_DISPLAY_DRAWN = 19;
private static final int ON_TASK_DISPLAY_CHANGED = 20;
private static final int ON_TASK_LIST_UPDATED = 21;
private static final int ON_SINGLE_TASK_DISPLAY_EMPTY = 22;
private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 23;
private static final int ON_TASK_DESCRIPTION_CHANGED = 24;
private static final int ON_ACTIVITY_ROTATION = 25;
private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 17;
private static final int ON_TASK_DISPLAY_CHANGED = 18;
private static final int ON_TASK_LIST_UPDATED = 19;
private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 20;
private static final int ON_TASK_DESCRIPTION_CHANGED = 21;
private static final int ON_ACTIVITY_ROTATION = 22;
private static final int ON_LOCK_TASK_MODE_CHANGED = 23;
/**
* List of {@link TaskStackChangeListener} registered from {@link #addListener}.
*/
private final List<TaskStackChangeListener> mTaskStackListeners = new ArrayList<>();
private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>();
public H(Looper looper) {
super(looper);
private final Handler mHandler;
private boolean mRegistered;
Impl(Looper looper) {
mHandler = new Handler(looper, this);
}
public void addListener(TaskStackChangeListener listener) {
synchronized (mTaskStackListeners) {
mTaskStackListeners.add(listener);
}
if (!mRegistered) {
// Register mTaskStackListener to IActivityManager only once if needed.
try {
ActivityTaskManager.getService().registerTaskStackListener(this);
mRegistered = true;
} catch (Exception e) {
Log.w(TAG, "Failed to call registerTaskStackListener", e);
}
}
}
public void removeListener(TaskStackChangeListener listener) {
boolean isEmpty;
synchronized (mTaskStackListeners) {
mTaskStackListeners.remove(listener);
isEmpty = mTaskStackListeners.isEmpty();
}
if (isEmpty && mRegistered) {
// Unregister mTaskStackListener once we have no more listeners
try {
ActivityTaskManager.getService().unregisterTaskStackListener(this);
mRegistered = false;
} catch (Exception e) {
Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
}
}
}
@Override
public void handleMessage(Message msg) {
public void onTaskStackChanged() {
// Call the task changed callback for the non-ui thread listeners first. Copy to a set
// of temp listeners so that we don't lock on mTaskStackListeners while calling all the
// callbacks. This call is always on the same binder thread, so we can just synchronize
// on the copying of the listener list.
synchronized (mTaskStackListeners) {
mTmpListeners.addAll(mTaskStackListeners);
}
for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
mTmpListeners.get(i).onTaskStackChangedBackground();
}
mTmpListeners.clear();
mHandler.removeMessages(ON_TASK_STACK_CHANGED);
mHandler.sendEmptyMessage(ON_TASK_STACK_CHANGED);
}
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
mHandler.removeMessages(ON_ACTIVITY_PINNED);
mHandler.obtainMessage(ON_ACTIVITY_PINNED,
new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget();
}
@Override
public void onActivityUnpinned() {
mHandler.removeMessages(ON_ACTIVITY_UNPINNED);
mHandler.sendEmptyMessage(ON_ACTIVITY_UNPINNED);
}
@Override
public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
boolean clearedTask, boolean wasVisible) {
final SomeArgs args = SomeArgs.obtain();
args.arg1 = task;
args.argi1 = homeTaskVisible ? 1 : 0;
args.argi2 = clearedTask ? 1 : 0;
args.argi3 = wasVisible ? 1 : 0;
mHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT);
mHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
}
@Override
public void onActivityForcedResizable(String packageName, int taskId, int reason) {
mHandler.obtainMessage(ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
.sendToTarget();
}
@Override
public void onActivityDismissingDockedTask() {
mHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
}
@Override
public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
int requestedDisplayId) {
mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED,
requestedDisplayId,
0 /* unused */,
taskInfo).sendToTarget();
}
@Override
public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
int requestedDisplayId) {
mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
}
@Override
public void onTaskProfileLocked(int taskId, int userId) {
mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
}
@Override
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
mHandler.obtainMessage(ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
}
@Override
public void onTaskCreated(int taskId, ComponentName componentName) {
mHandler.obtainMessage(ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
}
@Override
public void onTaskRemoved(int taskId) {
mHandler.obtainMessage(ON_TASK_REMOVED, taskId, 0).sendToTarget();
}
@Override
public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
mHandler.obtainMessage(ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
}
@Override
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
mHandler.obtainMessage(ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
}
@Override
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
mHandler.obtainMessage(ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
requestedOrientation).sendToTarget();
}
@Override
public void onTaskDisplayChanged(int taskId, int newDisplayId) {
mHandler.obtainMessage(ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
}
@Override
public void onRecentTaskListUpdated() {
mHandler.obtainMessage(ON_TASK_LIST_UPDATED).sendToTarget();
}
@Override
public void onRecentTaskListFrozenChanged(boolean frozen) {
mHandler.obtainMessage(ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
.sendToTarget();
}
@Override
public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) {
mHandler.obtainMessage(ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
}
@Override
public void onActivityRotation(int displayId) {
mHandler.obtainMessage(ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
.sendToTarget();
}
@Override
public void onLockTaskModeChanged(int mode) {
mHandler.obtainMessage(ON_LOCK_TASK_MODE_CHANGED, mode, 0 /* unused */).sendToTarget();
}
@Override
public boolean handleMessage(Message msg) {
synchronized (mTaskStackListeners) {
switch (msg.what) {
case ON_TASK_STACK_CHANGED: {
@@ -287,9 +292,10 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
case ON_TASK_SNAPSHOT_CHANGED: {
Trace.beginSection("onTaskSnapshotChanged");
final TaskSnapshot snapshot = (TaskSnapshot) msg.obj;
final ThumbnailData thumbnail = new ThumbnailData(snapshot);
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
new ThumbnailData((TaskSnapshot) msg.obj));
mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1, thumbnail);
}
Trace.endSection();
break;
@@ -298,7 +304,8 @@ public class TaskStackChangeListeners extends TaskStackListener {
final PinnedActivityInfo info = (PinnedActivityInfo) msg.obj;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onActivityPinned(
info.mPackageName, info.mUserId, info.mTaskId, info.mStackId);
info.mPackageName, info.mUserId, info.mTaskId,
info.mStackId);
}
break;
}
@@ -382,13 +389,6 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
break;
}
case ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onSizeCompatModeActivityChanged(
msg.arg1, (IBinder) msg.obj);
}
break;
}
case ON_BACK_PRESSED_ON_TASK_ROOT: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onBackPressedOnTaskRoot(
@@ -396,19 +396,6 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
break;
}
case ON_SINGLE_TASK_DISPLAY_DRAWN: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onSingleTaskDisplayDrawn(msg.arg1);
}
break;
}
case ON_SINGLE_TASK_DISPLAY_EMPTY: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onSingleTaskDisplayEmpty(
msg.arg1);
}
break;
}
case ON_TASK_DISPLAY_CHANGED: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onTaskDisplayChanged(msg.arg1, msg.arg2);
@@ -423,7 +410,8 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
case ON_TASK_LIST_FROZEN_UNFROZEN: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onRecentTaskListFrozenChanged(msg.arg1 != 0);
mTaskStackListeners.get(i).onRecentTaskListFrozenChanged(
msg.arg1 != 0);
}
break;
}
@@ -440,11 +428,18 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
break;
}
case ON_LOCK_TASK_MODE_CHANGED: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onLockTaskModeChanged(msg.arg1);
}
break;
}
}
}
if (msg.obj instanceof SomeArgs) {
((SomeArgs) msg.obj).recycle();
}
return true;
}
}
@@ -23,6 +23,7 @@ import android.view.ThreadedRenderer;
*/
public class ThreadedRendererCompat {
public static int EGL_CONTEXT_PRIORITY_REALTIME_NV = 0x3357;
public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
@@ -65,6 +65,11 @@ public class TransactionCompat {
return this;
}
public TransactionCompat setOpaque(SurfaceControlCompat surfaceControl, boolean opaque) {
mTransaction.setOpaque(surfaceControl.mSurfaceControl, opaque);
return this;
}
public TransactionCompat setMatrix(SurfaceControlCompat surfaceControl, float dsdx, float dtdx,
float dtdy, float dsdy) {
mTransaction.setMatrix(surfaceControl.mSurfaceControl, dsdx, dtdx, dtdy, dsdy);
@@ -92,34 +97,13 @@ public class TransactionCompat {
return this;
}
public TransactionCompat deferTransactionUntil(SurfaceControlCompat surfaceControl,
SurfaceControl barrier, long frameNumber) {
mTransaction.deferTransactionUntil(surfaceControl.mSurfaceControl, barrier,
frameNumber);
return this;
}
@Deprecated
public TransactionCompat setEarlyWakeup() {
return this;
}
public TransactionCompat setColor(SurfaceControlCompat surfaceControl, float[] color) {
mTransaction.setColor(surfaceControl.mSurfaceControl, color);
return this;
}
public static void deferTransactionUntil(Transaction t, SurfaceControl surfaceControl,
SurfaceControl barrier, long frameNumber) {
t.deferTransactionUntil(surfaceControl, barrier, frameNumber);
}
public static void setRelativeLayer(Transaction t, SurfaceControl surfaceControl,
SurfaceControl relativeTo, int z) {
t.setRelativeLayer(surfaceControl, relativeTo, z);
}
@Deprecated
public static void setEarlyWakeup(Transaction t) {
}
}
@@ -34,10 +34,6 @@ public class ViewRootImplCompat {
}
public SurfaceControl getRenderSurfaceControl() {
return mViewRoot == null ? null : mViewRoot.getRenderSurfaceControl();
}
public SurfaceControl getSurfaceControl() {
return mViewRoot == null ? null : mViewRoot.getSurfaceControl();
}
@@ -60,4 +56,12 @@ public class ViewRootImplCompat {
});
}
}
public void mergeWithNextTransaction(SurfaceControl.Transaction t, long frame) {
if (mViewRoot != null) {
mViewRoot.mergeWithNextTransaction(t, frame);
} else {
t.apply();
}
}
}
@@ -0,0 +1,179 @@
/*
* Copyright (C) 2020 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.shared.system;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.graphics.Region;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import java.util.HashMap;
public class ViewTreeObserverWrapper {
private static final HashMap<OnComputeInsetsListener, ViewTreeObserver>
sListenerObserverMap = new HashMap<>();
private static final HashMap<OnComputeInsetsListener, OnComputeInternalInsetsListener>
sListenerInternalListenerMap = new HashMap<>();
/**
* Register a callback to be invoked when the invoked when it is time to compute the window's
* insets.
*
* @param observer The observer to be added
* @param listener The callback to add
* @throws IllegalStateException If {@link ViewTreeObserver#isAlive()} returns false
*/
public static void addOnComputeInsetsListener(
@NonNull ViewTreeObserver observer, @NonNull OnComputeInsetsListener listener) {
final OnComputeInternalInsetsListener internalListener = internalInOutInfo -> {
final InsetsInfo inOutInfo = new InsetsInfo();
inOutInfo.contentInsets.set(internalInOutInfo.contentInsets);
inOutInfo.visibleInsets.set(internalInOutInfo.visibleInsets);
inOutInfo.touchableRegion.set(internalInOutInfo.touchableRegion);
listener.onComputeInsets(inOutInfo);
internalInOutInfo.contentInsets.set(inOutInfo.contentInsets);
internalInOutInfo.visibleInsets.set(inOutInfo.visibleInsets);
internalInOutInfo.touchableRegion.set(inOutInfo.touchableRegion);
internalInOutInfo.setTouchableInsets(inOutInfo.mTouchableInsets);
};
sListenerObserverMap.put(listener, observer);
sListenerInternalListenerMap.put(listener, internalListener);
observer.addOnComputeInternalInsetsListener(internalListener);
}
/**
* Remove a previously installed insets computation callback.
*
* @param victim The callback to remove
* @throws IllegalStateException If {@link ViewTreeObserver#isAlive()} returns false
* @see #addOnComputeInsetsListener(ViewTreeObserver, OnComputeInsetsListener)
*/
public static void removeOnComputeInsetsListener(@NonNull OnComputeInsetsListener victim) {
final ViewTreeObserver observer = sListenerObserverMap.get(victim);
final OnComputeInternalInsetsListener listener = sListenerInternalListenerMap.get(victim);
if (observer != null && listener != null) {
observer.removeOnComputeInternalInsetsListener(listener);
}
sListenerObserverMap.remove(victim);
sListenerInternalListenerMap.remove(victim);
}
/**
* Interface definition for a callback to be invoked when layout has
* completed and the client can compute its interior insets.
*/
public interface OnComputeInsetsListener {
/**
* Callback method to be invoked when layout has completed and the
* client can compute its interior insets.
*
* @param inoutInfo Should be filled in by the implementation with
* the information about the insets of the window. This is called
* with whatever values the previous OnComputeInsetsListener
* returned, if there are multiple such listeners in the window.
*/
void onComputeInsets(InsetsInfo inoutInfo);
}
/**
* Parameters used with OnComputeInsetsListener.
*/
public final static class InsetsInfo {
/**
* Offsets from the frame of the window at which the content of
* windows behind it should be placed.
*/
public final Rect contentInsets = new Rect();
/**
* Offsets from the frame of the window at which windows behind it
* are visible.
*/
public final Rect visibleInsets = new Rect();
/**
* Touchable region defined relative to the origin of the frame of the window.
* Only used when {@link #setTouchableInsets(int)} is called with
* the option {@link #TOUCHABLE_INSETS_REGION}.
*/
public final Region touchableRegion = new Region();
/**
* Option for {@link #setTouchableInsets(int)}: the entire window frame
* can be touched.
*/
public static final int TOUCHABLE_INSETS_FRAME =
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
/**
* Option for {@link #setTouchableInsets(int)}: the area inside of
* the content insets can be touched.
*/
public static final int TOUCHABLE_INSETS_CONTENT =
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
/**
* Option for {@link #setTouchableInsets(int)}: the area inside of
* the visible insets can be touched.
*/
public static final int TOUCHABLE_INSETS_VISIBLE =
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
/**
* Option for {@link #setTouchableInsets(int)}: the area inside of
* the provided touchable region in {@link #touchableRegion} can be touched.
*/
public static final int TOUCHABLE_INSETS_REGION =
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
/**
* Set which parts of the window can be touched: either
* {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
* {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
*/
public void setTouchableInsets(int val) {
mTouchableInsets = val;
}
int mTouchableInsets;
@Override
public int hashCode() {
int result = contentInsets.hashCode();
result = 31 * result + visibleInsets.hashCode();
result = 31 * result + touchableRegion.hashCode();
result = 31 * result + mTouchableInsets;
return result;
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final InsetsInfo other = (InsetsInfo) o;
return mTouchableInsets == other.mTouchableInsets &&
contentInsets.equals(other.contentInsets) &&
visibleInsets.equals(other.visibleInsets) &&
touchableRegion.equals(other.touchableRegion);
}
}
}
@@ -1,109 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.shared.system;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RecordingCanvas;
import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowCallbacks;
public class WindowCallbacksCompat {
private final WindowCallbacks mWindowCallbacks = new WindowCallbacks() {
@Override
public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
Rect stableInsets) {
WindowCallbacksCompat.this.onWindowSizeIsChanging(newBounds, fullscreen, systemInsets,
stableInsets);
}
@Override
public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen,
Rect systemInsets, Rect stableInsets, int resizeMode) {
WindowCallbacksCompat.this.onWindowDragResizeStart(initialBounds, fullscreen,
systemInsets, stableInsets, resizeMode);
}
@Override
public void onWindowDragResizeEnd() {
WindowCallbacksCompat.this.onWindowDragResizeEnd();
}
@Override
public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
return WindowCallbacksCompat.this.onContentDrawn(offsetX, offsetY, sizeX, sizeY);
}
@Override
public void onRequestDraw(boolean reportNextDraw) {
WindowCallbacksCompat.this.onRequestDraw(reportNextDraw);
}
@Override
public void onPostDraw(RecordingCanvas canvas) {
WindowCallbacksCompat.this.onPostDraw(canvas);
}
};
private final View mView;
public WindowCallbacksCompat(View view) {
mView = view;
}
public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
Rect stableInsets) { }
public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
Rect stableInsets, int resizeMode) { }
public void onWindowDragResizeEnd() { }
public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
return false;
}
public void onRequestDraw(boolean reportNextDraw) {
if (reportNextDraw) {
reportDrawFinish();
}
}
public void onPostDraw(Canvas canvas) { }
public void reportDrawFinish() {
mView.getViewRootImpl().reportDrawFinish();
}
public boolean attach() {
ViewRootImpl root = mView.getViewRootImpl();
if (root != null) {
root.addWindowCallbacks(mWindowCallbacks);
root.requestInvalidateRootRenderNode();
return true;
}
return false;
}
public void detach() {
ViewRootImpl root = mView.getViewRootImpl();
if (root != null) {
root.removeWindowCallbacks(mWindowCallbacks);
}
}
}
@@ -27,41 +27,41 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
public class WindowManagerWrapper {
private static final String TAG = "WindowManagerWrapper";
public static final int TRANSIT_UNSET = WindowManager.TRANSIT_UNSET;
public static final int TRANSIT_NONE = WindowManager.TRANSIT_NONE;
public static final int TRANSIT_ACTIVITY_OPEN = WindowManager.TRANSIT_ACTIVITY_OPEN;
public static final int TRANSIT_ACTIVITY_CLOSE = WindowManager.TRANSIT_ACTIVITY_CLOSE;
public static final int TRANSIT_TASK_OPEN = WindowManager.TRANSIT_TASK_OPEN;
public static final int TRANSIT_TASK_CLOSE = WindowManager.TRANSIT_TASK_CLOSE;
public static final int TRANSIT_TASK_TO_FRONT = WindowManager.TRANSIT_TASK_TO_FRONT;
public static final int TRANSIT_TASK_TO_BACK = WindowManager.TRANSIT_TASK_TO_BACK;
public static final int TRANSIT_WALLPAPER_CLOSE = WindowManager.TRANSIT_WALLPAPER_CLOSE;
public static final int TRANSIT_WALLPAPER_OPEN = WindowManager.TRANSIT_WALLPAPER_OPEN;
public static final int TRANSIT_UNSET = WindowManager.TRANSIT_OLD_UNSET;
public static final int TRANSIT_NONE = WindowManager.TRANSIT_OLD_NONE;
public static final int TRANSIT_ACTIVITY_OPEN = WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
public static final int TRANSIT_ACTIVITY_CLOSE = WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
public static final int TRANSIT_TASK_OPEN = WindowManager.TRANSIT_OLD_TASK_OPEN;
public static final int TRANSIT_TASK_CLOSE = WindowManager.TRANSIT_OLD_TASK_CLOSE;
public static final int TRANSIT_TASK_TO_FRONT = WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
public static final int TRANSIT_TASK_TO_BACK = WindowManager.TRANSIT_OLD_TASK_TO_BACK;
public static final int TRANSIT_WALLPAPER_CLOSE = WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE;
public static final int TRANSIT_WALLPAPER_OPEN = WindowManager.TRANSIT_OLD_WALLPAPER_OPEN;
public static final int TRANSIT_WALLPAPER_INTRA_OPEN =
WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
public static final int TRANSIT_WALLPAPER_INTRA_CLOSE =
WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
public static final int TRANSIT_TASK_OPEN_BEHIND = WindowManager.TRANSIT_TASK_OPEN_BEHIND;
public static final int TRANSIT_ACTIVITY_RELAUNCH = WindowManager.TRANSIT_ACTIVITY_RELAUNCH;
public static final int TRANSIT_DOCK_TASK_FROM_RECENTS =
WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
public static final int TRANSIT_KEYGUARD_GOING_AWAY = WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
public static final int TRANSIT_TASK_OPEN_BEHIND = WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
public static final int TRANSIT_ACTIVITY_RELAUNCH = WindowManager.TRANSIT_OLD_ACTIVITY_RELAUNCH;
public static final int TRANSIT_KEYGUARD_GOING_AWAY =
WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
public static final int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER =
WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
public static final int TRANSIT_KEYGUARD_UNOCCLUDE = WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
public static final int TRANSIT_KEYGUARD_UNOCCLUDE =
WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
public static final int NAV_BAR_POS_INVALID = NAV_BAR_INVALID;
public static final int NAV_BAR_POS_LEFT = NAV_BAR_LEFT;
@@ -75,26 +75,49 @@ public class WindowManagerWrapper {
WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
public static final int WINDOWING_MODE_MULTI_WINDOW =
WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
public static final int WINDOWING_MODE_PINNED = WindowConfiguration.WINDOWING_MODE_PINNED;
public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY =
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY =
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
public static final int WINDOWING_MODE_FREEFORM = WindowConfiguration.WINDOWING_MODE_FREEFORM;
private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
public static final int ITYPE_EXTRA_NAVIGATION_BAR = InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = InsetsState.ITYPE_LEFT_TAPPABLE_ELEMENT;
public static final int ITYPE_TOP_TAPPABLE_ELEMENT = InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
public static final int ITYPE_RIGHT_TAPPABLE_ELEMENT = InsetsState.ITYPE_RIGHT_TAPPABLE_ELEMENT;
public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT =
InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
/**
* Forwarder to which we can add multiple pinned stack listeners. Each listener will receive
* updates from the window manager service.
*/
private PinnedStackListenerForwarder mPinnedStackListenerForwarder =
new PinnedStackListenerForwarder();
private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
public static WindowManagerWrapper getInstance() {
return sInstance;
}
/**
* Sets {@param providesInsetsTypes} as the inset types provided by {@param params}.
* @param params The window layout params.
* @param providesInsetsTypes The inset types we would like this layout params to provide.
*/
public void setProvidesInsetsTypes(WindowManager.LayoutParams params,
int[] providesInsetsTypes) {
params.providesInsetsTypes = providesInsetsTypes;
}
/**
* Sets if app requested fixed orientation should be ignored for given displayId.
*/
public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
try {
WindowManagerGlobal.getWindowManagerService().setIgnoreOrientationRequest(
displayId, ignoreOrientationRequest);
} catch (RemoteException e) {
Log.e(TAG, "Failed to setIgnoreOrientationRequest()", e);
}
}
/**
* @return the stable insets for the primary display.
*/
@@ -153,12 +176,9 @@ public class WindowManagerWrapper {
}
}
@Deprecated
public void setPipVisibility(final boolean visible) {
try {
WindowManagerGlobal.getWindowManagerService().setPipVisibility(visible);
} catch (RemoteException e) {
Log.e(TAG, "Unable to reach window manager", e);
}
// To be removed
}
/**
@@ -190,23 +210,6 @@ public class WindowManagerWrapper {
return NAV_BAR_POS_INVALID;
}
/**
* Adds a pinned stack listener, which will receive updates from the window manager service
* along with any other pinned stack listeners that were added via this method.
*/
public void addPinnedStackListener(PinnedStackListener listener) throws RemoteException {
mPinnedStackListenerForwarder.addListener(listener);
WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
DEFAULT_DISPLAY, mPinnedStackListenerForwarder);
}
/**
* Removes a pinned stack listener.
*/
public void removePinnedStackListener(PinnedStackListener listener) {
mPinnedStackListenerForwarder.removeListener(listener);
}
/**
* Mirrors a specified display. The SurfaceControl returned is the root of the mirrored
* hierarchy.
@@ -0,0 +1,34 @@
/*
* 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.shared.system.smartspace;
import com.android.systemui.shared.system.smartspace.SmartspaceState;
// Methods for getting and setting the state of a SmartSpace. This is used to allow a remote process
// (such as System UI) to sync with and control a SmartSpace view hosted in another process (such as
// Launcher).
interface ISmartspaceCallback {
// Return information about the state of the SmartSpace, including location on-screen and
// currently selected page.
SmartspaceState getSmartspaceState();
// Set the currently selected page of this SmartSpace.
oneway void setSelectedPage(int selectedPage);
oneway void setVisibility(int visibility);
}
@@ -0,0 +1,24 @@
/*
* 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.shared.system.smartspace;
import com.android.systemui.shared.system.smartspace.ISmartspaceCallback;
// Controller that keeps track of SmartSpace instances in remote processes (such as Launcher).
interface ISmartspaceTransitionController {
oneway void setSmartspace(ISmartspaceCallback callback);
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 The Android Open Source Project
* 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.
@@ -11,18 +11,11 @@
* 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
* limitations under the License.
*/
package com.android.systemui.shared.system;
package com.android.systemui.shared.system.smartspace;
import android.graphics.Bitmap;
import android.os.Bundle;
import com.android.systemui.shared.system.smartspace.SmartspaceState;
/**
* Abstract class for assist data receivers.
*/
public abstract class AssistDataReceiver {
public void onHandleAssistData(Bundle resultData) {}
public void onHandleAssistScreenshot(Bitmap screenshot) {}
}
parcelable SmartspaceState;
@@ -0,0 +1,59 @@
/*
* 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.shared.system.smartspace
import android.graphics.Rect
import android.os.Parcel
import android.os.Parcelable
/**
* Represents the state of a SmartSpace, including its location on screen and the index of the
* currently selected page. This object contains all of the information needed to synchronize two
* SmartSpace instances so that we can perform shared-element transitions between them.
*/
class SmartspaceState() : Parcelable {
var boundsOnScreen: Rect = Rect()
var selectedPage = 0
constructor(parcel: Parcel) : this() {
this.boundsOnScreen = parcel.readParcelable(Rect::javaClass.javaClass.classLoader)!!
this.selectedPage = parcel.readInt()
}
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeParcelable(boundsOnScreen, 0)
dest?.writeInt(selectedPage)
}
override fun describeContents(): Int {
return 0
}
override fun toString(): String {
return "boundsOnScreen: $boundsOnScreen, selectedPage: $selectedPage"
}
companion object CREATOR : Parcelable.Creator<SmartspaceState> {
override fun createFromParcel(parcel: Parcel): SmartspaceState {
return SmartspaceState(parcel)
}
override fun newArray(size: Int): Array<SmartspaceState?> {
return arrayOfNulls(size)
}
}
}
@@ -49,7 +49,7 @@ public class FrameProtoTracer<P, S extends P, T extends P, R>
private final TraceBuffer<P, S, T> mBuffer;
private final File mTraceFile;
private final ProtoTraceParams<P, S, T, R> mParams;
private final Choreographer mChoreographer;
private Choreographer mChoreographer;
private final Queue<T> mPool = new LinkedList<>();
private final ArrayList<ProtoTraceable<R>> mTraceables = new ArrayList<>();
private final ArrayList<ProtoTraceable<R>> mTmpTraceables = new ArrayList<>();
@@ -94,7 +94,6 @@ public class FrameProtoTracer<P, S extends P, T extends P, R>
}
});
mTraceFile = params.getTraceFile();
mChoreographer = Choreographer.getMainThreadInstance();
}
public void start() {
@@ -140,6 +139,9 @@ public class FrameProtoTracer<P, S extends P, T extends P, R>
}
// Schedule an update on the next frame
if (mChoreographer == null) {
mChoreographer = Choreographer.getMainThreadInstance();
}
mChoreographer.postFrameCallback(this);
mFrameScheduled = true;
}