diff --git a/SystemUIShared/build.gradle b/SystemUIShared/build.gradle index e97e0aa84d..b99e5b9b6b 100644 --- a/SystemUIShared/build.gradle +++ b/SystemUIShared/build.gradle @@ -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" } diff --git a/SystemUIShared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/SystemUIShared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java new file mode 100644 index 0000000000..7d0fb5d388 --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java @@ -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; + } +} diff --git a/SystemUIShared/src/com/android/systemui/shared/plugins/PluginEnabler.java b/SystemUIShared/src/com/android/systemui/shared/plugins/PluginEnabler.java index 01b012d1fc..1c5da827ee 100644 --- a/SystemUIShared/src/com/android/systemui/shared/plugins/PluginEnabler.java +++ b/SystemUIShared/src/com/android/systemui/shared/plugins/PluginEnabler.java @@ -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}) diff --git a/SystemUIShared/src/com/android/systemui/shared/plugins/PluginInitializer.java b/SystemUIShared/src/com/android/systemui/shared/plugins/PluginInitializer.java index c3815e4cee..42bc1d0ea0 100644 --- a/SystemUIShared/src/com/android/systemui/shared/plugins/PluginInitializer.java +++ b/SystemUIShared/src/com/android/systemui/shared/plugins/PluginInitializer.java @@ -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(); } diff --git a/SystemUIShared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/SystemUIShared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java index c8607df8fe..2b35bcd9a3 100644 --- a/SystemUIShared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java +++ b/SystemUIShared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java @@ -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 { PluginInstanceManager(Context context, String action, PluginListener 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 { } 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()); diff --git a/SystemUIShared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/SystemUIShared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java index 843914b272..c89aa00d5e 100644 --- a/SystemUIShared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java +++ b/SystemUIShared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java @@ -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, PluginInstanceManager> mPluginMap = new ArrayMap<>(); private final Map mClassLoaders = new ArrayMap<>(); @@ -75,7 +73,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage private final ArraySet 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; diff --git a/SystemUIShared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/SystemUIShared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl index 114472b15f..277b2e31f7 100644 --- a/SystemUIShared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl +++ b/SystemUIShared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl @@ -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; } diff --git a/SystemUIShared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/SystemUIShared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 655008b774..f72245b9b2 100644 --- a/SystemUIShared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/SystemUIShared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -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 } diff --git a/SystemUIShared/src/com/android/systemui/shared/recents/model/Task.java b/SystemUIShared/src/com/android/systemui/shared/recents/model/Task.java index 186379af4b..e9e9b2421d 100644 --- a/SystemUIShared/src/com/android/systemui/shared/recents/model/Task.java +++ b/SystemUIShared/src/com/android/systemui/shared/recents/model/Task.java @@ -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 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"); } diff --git a/SystemUIShared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/SystemUIShared/src/com/android/systemui/shared/recents/model/ThumbnailData.java index 1e505801c2..6594d5f51a 100644 --- a/SystemUIShared/src/com/android/systemui/shared/recents/model/ThumbnailData.java +++ b/SystemUIShared/src/com/android/systemui/shared/recents/model/ThumbnailData.java @@ -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(); } } diff --git a/SystemUIShared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java b/SystemUIShared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java index b79fcbd439..325bcfc622 100644 --- a/SystemUIShared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java +++ b/SystemUIShared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java @@ -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()); } } diff --git a/SystemUIShared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java b/SystemUIShared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java index ebdc884285..a6fdfc43a1 100644 --- a/SystemUIShared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java @@ -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); } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/SystemUIShared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index cffc10f65f..9164137feb 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -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 tasks = - ActivityTaskManager.getService().getFilteredTasks(1, filterOnlyVisibleRecents); - if (tasks.isEmpty()) { - return null; - } - return tasks.get(0); - } catch (RemoteException e) { + List tasks = + mAtm.getTasks(1, filterOnlyVisibleRecents); + if (tasks.isEmpty()) { return null; } + return tasks.get(0); } /** * @return a list of the recents tasks. */ public List 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 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 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 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 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; } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java index 345a649a03..e2ca349cc5 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java @@ -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); + } + } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/BackgroundExecutor.java b/SystemUIShared/src/com/android/systemui/shared/system/BackgroundExecutor.java deleted file mode 100644 index 0bd89a78cf..0000000000 --- a/SystemUIShared/src/com/android/systemui/shared/system/BackgroundExecutor.java +++ /dev/null @@ -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 Future submit(Callable 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 Future submit(Runnable runnable, T result) { - return mExecutorService.submit(runnable, result); - } -} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/BlurUtils.java b/SystemUIShared/src/com/android/systemui/shared/system/BlurUtils.java index 9f26d851f7..61b0e4d902 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/BlurUtils.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/BlurUtils.java @@ -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); } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/ChoreographerCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/ChoreographerCompat.java deleted file mode 100644 index 76b447e3fa..0000000000 --- a/SystemUIShared/src/com/android/systemui/shared/system/ChoreographerCompat.java +++ /dev/null @@ -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(); - } -} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java new file mode 100644 index 0000000000..0b1141ee9b --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java @@ -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; +} diff --git a/SystemUIShared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl b/SystemUIShared/src/com/android/systemui/shared/system/ContextUtils.java similarity index 66% rename from SystemUIShared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl rename to SystemUIShared/src/com/android/systemui/shared/system/ContextUtils.java index 97aa512ea7..1de740a083 100644 --- a/SystemUIShared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl +++ b/SystemUIShared/src/com/android/systemui/shared/system/ContextUtils.java @@ -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(); + } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/InputChannelCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/InputChannelCompat.java index 2b1fce8a4c..259cca8c01 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/InputChannelCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/InputChannelCompat.java @@ -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(); } } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/InputConsumerController.java b/SystemUIShared/src/com/android/systemui/shared/system/InputConsumerController.java index 27e4c85e1e..bf23a49df2 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/InputConsumerController.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/InputConsumerController.java @@ -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); diff --git a/SystemUIShared/src/com/android/systemui/shared/system/InputMonitorCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/InputMonitorCompat.java index ddca7234c9..bf8e6a5663 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/InputMonitorCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/InputMonitorCompat.java @@ -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)); - } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/SystemUIShared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java new file mode 100644 index 0000000000..442716878a --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java @@ -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); + } +} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java index 0d5933e5f5..a8c19ec241 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java @@ -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); } } \ No newline at end of file diff --git a/SystemUIShared/src/com/android/systemui/shared/system/LauncherAppsCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/LauncherAppsCompat.java new file mode 100644 index 0000000000..d24c779b14 --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/LauncherAppsCompat.java @@ -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); + } +} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/LauncherEventUtil.java b/SystemUIShared/src/com/android/systemui/shared/system/LauncherEventUtil.java index eed9580e22..a51d668c82 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/LauncherEventUtil.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/LauncherEventUtil.java @@ -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; - } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/PeopleProviderUtils.java b/SystemUIShared/src/com/android/systemui/shared/system/PeopleProviderUtils.java new file mode 100644 index 0000000000..15cf3696fe --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/PeopleProviderUtils.java @@ -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"; + +} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java b/SystemUIShared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java deleted file mode 100644 index 4794847d8b..0000000000 --- a/SystemUIShared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java +++ /dev/null @@ -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 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) {} - } -} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/QuickStepContract.java b/SystemUIShared/src/com/android/systemui/shared/system/QuickStepContract.java index 7657185827..c468e416f8 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -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); } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index 76513c6ff3..8e65560f7c 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -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; } } -} \ No newline at end of file + + /** + * @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); + } + } +} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java index 02e509eef2..ee55bf0aa8 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java @@ -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 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 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. + } + }; + } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java index 33372f6bd0..007629254c 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java @@ -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(); } \ No newline at end of file diff --git a/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java index aed7c21643..2407d216b4 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java @@ -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 leashMap) { + final ArrayList 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(); } } -} \ No newline at end of file +} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/ContextCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl similarity index 61% rename from SystemUIShared/src/com/android/systemui/shared/system/ContextCompat.java rename to SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl index 51fcb0a841..1550ab3bed 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/ContextCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl @@ -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; diff --git a/SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java new file mode 100644 index 0000000000..653d73020c --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -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 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 mLeashMap = null; + + void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info, + IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask, + ArrayMap 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 CREATOR + = new Parcelable.Creator() { + @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 + +} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionRunner.java b/SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionRunner.java new file mode 100644 index 0000000000..accc456c42 --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/RemoteTransitionRunner.java @@ -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) { } +} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java index 2985a61dec..e281914d56 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java @@ -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); + } } } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/TaskInfoCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/TaskInfoCompat.java deleted file mode 100644 index 326c2aa371..0000000000 --- a/SystemUIShared/src/com/android/systemui/shared/system/TaskInfoCompat.java +++ /dev/null @@ -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; - } -} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/SystemUIShared/src/com/android/systemui/shared/system/TaskStackChangeListener.java index 44372d76bb..c5d5439195 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/TaskStackChangeListener.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/TaskStackChangeListener.java @@ -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) { } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/SystemUIShared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java index f214648d89..b5019b426a 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java @@ -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 mTaskStackListeners = new ArrayList<>(); - private final List 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 mTaskStackListeners = new ArrayList<>(); + private final List 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; } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java index bf88a29184..ffd8a08905 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java @@ -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; diff --git a/SystemUIShared/src/com/android/systemui/shared/system/TransactionCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/TransactionCompat.java index 255fffdb32..c043fba482 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/TransactionCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/TransactionCompat.java @@ -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) { - } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/ViewRootImplCompat.java index 73783ae7ec..89c60f1d3f 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/ViewRootImplCompat.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/ViewRootImplCompat.java @@ -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(); + } + } } diff --git a/SystemUIShared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java b/SystemUIShared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java new file mode 100644 index 0000000000..cfb23f9e4f --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java @@ -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 + sListenerObserverMap = new HashMap<>(); + private static final HashMap + 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); + } + } +} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java b/SystemUIShared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java deleted file mode 100644 index de2a3e4484..0000000000 --- a/SystemUIShared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java +++ /dev/null @@ -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); - } - } -} diff --git a/SystemUIShared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/SystemUIShared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index d64bf77ad9..b38270cb86 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -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. diff --git a/SystemUIShared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl b/SystemUIShared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl new file mode 100644 index 0000000000..511df4c285 --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl @@ -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); +} \ No newline at end of file diff --git a/SystemUIShared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl b/SystemUIShared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl new file mode 100644 index 0000000000..2b3e961ab3 --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl @@ -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); +} \ No newline at end of file diff --git a/SystemUIShared/src/com/android/systemui/shared/system/AssistDataReceiver.java b/SystemUIShared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl similarity index 56% rename from SystemUIShared/src/com/android/systemui/shared/system/AssistDataReceiver.java rename to SystemUIShared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl index 7cd6c512b6..2d01d6af63 100644 --- a/SystemUIShared/src/com/android/systemui/shared/system/AssistDataReceiver.java +++ b/SystemUIShared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl @@ -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; \ No newline at end of file diff --git a/SystemUIShared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt b/SystemUIShared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt new file mode 100644 index 0000000000..f0edc95016 --- /dev/null +++ b/SystemUIShared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt @@ -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 { + override fun createFromParcel(parcel: Parcel): SmartspaceState { + return SmartspaceState(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/SystemUIShared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java b/SystemUIShared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java index 356e0ca719..4394ecbf79 100644 --- a/SystemUIShared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java +++ b/SystemUIShared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java @@ -49,7 +49,7 @@ public class FrameProtoTracer private final TraceBuffer mBuffer; private final File mTraceFile; private final ProtoTraceParams mParams; - private final Choreographer mChoreographer; + private Choreographer mChoreographer; private final Queue mPool = new LinkedList<>(); private final ArrayList> mTraceables = new ArrayList<>(); private final ArrayList> mTmpTraceables = new ArrayList<>(); @@ -94,7 +94,6 @@ public class FrameProtoTracer } }); mTraceFile = params.getTraceFile(); - mChoreographer = Choreographer.getMainThreadInstance(); } public void start() { @@ -140,6 +139,9 @@ public class FrameProtoTracer } // Schedule an update on the next frame + if (mChoreographer == null) { + mChoreographer = Choreographer.getMainThreadInstance(); + } mChoreographer.postFrameCallback(this); mFrameScheduled = true; }