QuickSwitch Compat Q to U (#3948)

Initial support quickstep, Android versions from Q to U, ensuring a smooth and efficient user experience. Enjoy effortless navigation and swift app switching on your Android device with QuickSwitch's compatibility across the Q, R, S, T, and U.


Co-authored-by: Goooler <wangzongler@gmail.com>
Co-authored-by: 无言 <57122860+liu-wanshun@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2024-01-26 05:59:47 +08:00
1 parent f63aa1e315
commit c31b41ae73
111 files changed
+4547 -602

No files matched your search

+23 -2
View File
@@ -92,6 +92,9 @@ allprojects {
libraries.from(files(frameworkJar))
}
}
dependencies {
compileOnly files(frameworkJar)
}
}
compileOnlyCommonJars = {
@@ -99,7 +102,13 @@ allprojects {
compileOnly fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'SystemUI-core.jar')
compileOnly fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'SystemUI-statsd.jar')
compileOnly fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'WindowManager-Shell-14.jar')
compileOnly fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'framework-14.jar')
compileOnly projects.compatLib
compileOnly projects.compatLib.compatLibVQ
compileOnly projects.compatLib.compatLibVR
compileOnly projects.compatLib.compatLibVS
compileOnly projects.compatLib.compatLibVT
compileOnly projects.compatLib.compatLibVU
}
}
}
@@ -119,7 +128,7 @@ final def releaseName = "Beta 1"
final def versionDisplayName = "${version} ${isReleaseBuild ? releaseName : devReleaseName}"
final def majorVersion = versionDisplayName.split("\\.")[0]
final def quickstepMinSdk = "34"
final def quickstepMinSdk = "29"
final def quickstepMaxSdk = "34"
android {
@@ -320,6 +329,14 @@ dependencies {
withQuickstepImplementation projects.systemUIPluginCore
withQuickstepCompileOnly projects.systemUICommon
// QuickSwitch Compat
withQuickstepImplementation projects.compatLib
withQuickstepImplementation projects.compatLib.compatLibVQ
withQuickstepImplementation projects.compatLib.compatLibVR
withQuickstepImplementation projects.compatLib.compatLibVS
withQuickstepImplementation projects.compatLib.compatLibVT
withQuickstepImplementation projects.compatLib.compatLibVU
implementation fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'SystemUI-statsd-14.jar')
implementation fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'WindowManager-Shell-14.jar')
@@ -398,6 +415,10 @@ ksp {
}
spotless {
java {
target("compatLib/**/src/**/*.java")
googleJavaFormat().aosp()
}
kotlin {
target("lawnchair/src/**/*.kt")
ktlint().customRuleSets([
+1
View File
@@ -0,0 +1 @@
# Lawnchair Quickstep Compat Lib
+11 -1
View File
@@ -4,6 +4,16 @@ plugins {
android {
namespace "app.lawnchair.compatlib"
buildFeatures {
aidl true
}
sourceSets {
main {
aidl.srcDirs = ['src/main/java']
}
}
}
addFrameworkJar('framework-12.jar')
addFrameworkJar('framework-14.jar')
+14
View File
@@ -0,0 +1,14 @@
plugins {
id 'com.android.library'
}
android {
namespace "app.lawnchair.compatlib.ten"
}
addFrameworkJar('framework-10.jar')
dependencies {
implementation projects.compatLib
implementation projects.compatLib.compatLibVR
}
@@ -0,0 +1,123 @@
package app.lawnchair.compatlib.ten;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.WindowConfiguration;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.RemoteException;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import app.lawnchair.compatlib.RecentsAnimationRunnerCompat;
import app.lawnchair.compatlib.eleven.ActivityManagerCompatVR;
import java.util.List;
public class ActivityManagerCompatVQ extends ActivityManagerCompatVR {
@Override
public void invalidateHomeTaskSnapshot(Activity homeActivity) {
// do nothing ,android Q not support
}
@Override
public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
int ignoreActivityType = WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
if (filterOnlyVisibleRecents) {
ignoreActivityType = WindowConfiguration.ACTIVITY_TYPE_RECENTS;
}
try {
List<ActivityManager.RunningTaskInfo> tasks =
ActivityTaskManager.getService()
.getFilteredTasks(
NUM_RECENT_ACTIVITIES_REQUEST,
ignoreActivityType,
WindowConfiguration.WINDOWING_MODE_PINNED);
if (tasks.isEmpty()) {
return null;
}
return tasks.toArray(new ActivityManager.RunningTaskInfo[tasks.size()]);
} catch (RemoteException e) {
return null;
}
}
@Override
public void startRecentsActivity(
Intent intent, long eventTime, RecentsAnimationRunnerCompat runnerCompat) {
IRecentsAnimationRunner runner = null;
if (runnerCompat != null) {
runner =
new IRecentsAnimationRunner.Stub() {
@Override
public void onAnimationStart(
IRecentsAnimationController controller,
RemoteAnimationTarget[] apps,
Rect homeContentInsets,
Rect minimizedHomeBounds) {
runnerCompat.onAnimationStart(
controller, apps, null, homeContentInsets, minimizedHomeBounds);
}
public void reportAllDrawn() {}
@Override
public void onAnimationCanceled(boolean deferredWithScreenshot) {
runnerCompat.onAnimationCanceled(deferredWithScreenshot);
}
};
}
try {
ActivityTaskManager.getService().startRecentsActivity(intent, null, runner);
} catch (RemoteException e) {
}
}
@Override
public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
int ignoreActivityType = WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
if (filterOnlyVisibleRecents) {
ignoreActivityType = WindowConfiguration.ACTIVITY_TYPE_RECENTS;
}
try {
List<ActivityManager.RunningTaskInfo> tasks =
ActivityTaskManager.getService()
.getFilteredTasks(
1,
ignoreActivityType,
WindowConfiguration.WINDOWING_MODE_PINNED);
if (tasks.isEmpty()) {
return null;
}
return tasks.get(0);
} catch (RemoteException e) {
return null;
}
}
@Override
public ThumbnailData makeThumbnailData(ActivityManager.TaskSnapshot snapshot) {
ThumbnailData data = new ThumbnailData();
data.thumbnail =
Bitmap.wrapHardwareBuffer(snapshot.getSnapshot(), snapshot.getColorSpace());
data.insets = new Rect(snapshot.getContentInsets());
data.orientation = snapshot.getOrientation();
data.reducedResolution = snapshot.isReducedResolution();
// TODO(b/149579527): Pass task size instead of computing scale.
// Assume width and height were scaled the same; compute scale only for width
data.scale = snapshot.getScale();
data.isRealSnapshot = snapshot.isRealSnapshot();
data.isTranslucent = snapshot.isTranslucent();
data.windowingMode = snapshot.getWindowingMode();
data.systemUiVisibility = snapshot.getSystemUiVisibility();
return data;
}
}
@@ -0,0 +1,39 @@
package app.lawnchair.compatlib.ten;
import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
import android.view.RemoteAnimationAdapter;
import app.lawnchair.compatlib.ActivityOptionsCompat;
public class ActivityOptionsCompatVQ extends ActivityOptionsCompat {
@Override
public ActivityOptions makeCustomAnimation(
Context context,
int enterResId,
int exitResId,
Runnable callback,
Handler callbackHandler) {
return ActivityOptions.makeCustomAnimation(
context,
enterResId,
exitResId,
callbackHandler,
new ActivityOptions.OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
if (callback != null) {
callbackHandler.post(callback);
}
}
});
}
@Override
public ActivityOptions makeRemoteAnimation(
RemoteAnimationAdapter remoteAnimationAdapter,
Object remoteTransition,
String debugName) {
return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter);
}
}
@@ -0,0 +1,21 @@
package app.lawnchair.compatlib.ten;
import androidx.annotation.NonNull;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.ActivityOptionsCompat;
import app.lawnchair.compatlib.eleven.QuickstepCompatFactoryVR;
public class QuickstepCompatFactoryVQ extends QuickstepCompatFactoryVR {
@NonNull
@Override
public ActivityManagerCompat getActivityManagerCompat() {
return new ActivityManagerCompatVQ();
}
@NonNull
@Override
public ActivityOptionsCompat getActivityOptionsCompat() {
return new ActivityOptionsCompatVQ();
}
}
File renamed without changes.
@@ -4,6 +4,7 @@ import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.ActivityTaskManager.getService;
import static android.graphics.Bitmap.Config.ARGB_8888;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.Intent;
@@ -18,41 +19,63 @@ import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.RecentsAnimationRunnerCompat;
import java.util.ArrayList;
import java.util.List;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.RecentsAnimationRunnerStub;
public class ActivityManagerCompatVR extends ActivityManagerCompat {
private static final String TAG = "ActivityManagerCompatVR";
@Override
public void startRecentsActivity(Intent intent, long eventTime, RecentsAnimationRunnerStub runner) throws RemoteException {
IRecentsAnimationRunner wrappedRunner = null;
if (runner != null) {
wrappedRunner = new IRecentsAnimationRunner.Stub() {
@Override
public void onAnimationStart(IRecentsAnimationController controller,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
Rect homeContentInsets, Rect minimizedHomeBounds) {
runner.onAnimationStart(controller, apps, wallpapers, homeContentInsets, minimizedHomeBounds);
}
public void invalidateHomeTaskSnapshot(Activity homeActivity) {
try {
ActivityTaskManager.getService()
.invalidateHomeTaskSnapshot(homeActivity.getActivityToken());
} catch (RemoteException e) {
Log.w(TAG, "Failed to invalidate home snapshot", e);
}
}
@Override
public void onAnimationCanceled(ActivityManager.TaskSnapshot taskSnapshot) {
runner.onAnimationCanceled(taskSnapshot);
}
@Override
public void startRecentsActivity(
Intent intent, long eventTime, RecentsAnimationRunnerCompat runnerCompat) {
IRecentsAnimationRunner runner = null;
if (runnerCompat != null) {
runner =
new IRecentsAnimationRunner.Stub() {
@Override
public void onAnimationStart(
IRecentsAnimationController controller,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
Rect homeContentInsets,
Rect minimizedHomeBounds) {
runnerCompat.onAnimationStart(
controller,
apps,
wallpapers,
homeContentInsets,
minimizedHomeBounds);
}
@Override
public void onTaskAppeared(RemoteAnimationTarget app) {
runner.onTaskAppeared(app);
}
};
@Override
public void onAnimationCanceled(ActivityManager.TaskSnapshot taskSnapshot) {
runnerCompat.onAnimationCanceled(taskSnapshot);
}
@Override
public void onTaskAppeared(RemoteAnimationTarget app) {
runnerCompat.onTaskAppeared(app);
}
};
}
try {
getService().startRecentsActivity(intent, null, runner);
} catch (RemoteException e) {
Log.e(TAG, "Failed to cancel recents animation", e);
}
getService().startRecentsActivity(intent, null, wrappedRunner);
}
@Override
@@ -73,14 +96,31 @@ public class ActivityManagerCompatVR extends ActivityManagerCompat {
@Override
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
try {
return ActivityTaskManager.getService().getRecentTasks(numTasks,
RECENT_IGNORE_UNAVAILABLE, userId).getList();
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<>();
}
}
@Override
public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
try {
List<ActivityManager.RunningTaskInfo> tasks =
ActivityTaskManager.getService()
.getFilteredTasks(
NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents);
if (tasks.isEmpty()) {
return null;
}
return tasks.toArray(new ActivityManager.RunningTaskInfo[tasks.size()]);
} catch (RemoteException e) {
return null;
}
}
public ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
ActivityManager.TaskSnapshot snapshot = null;
try {
@@ -95,7 +135,8 @@ public class ActivityManagerCompatVR extends ActivityManagerCompat {
}
}
public ThumbnailData takeScreenshot(IRecentsAnimationController animationController, int taskId) {
public ThumbnailData takeScreenshot(
IRecentsAnimationController animationController, int taskId) {
try {
ActivityManager.TaskSnapshot snapshot = animationController.screenshotTask(taskId);
return snapshot != null ? makeThumbnailData(snapshot) : new ThumbnailData();
@@ -110,8 +151,9 @@ public class ActivityManagerCompatVR extends ActivityManagerCompat {
final GraphicBuffer buffer = snapshot.getSnapshot();
if (buffer == null || (buffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
// 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);
Log.e(
"ThumbnailData",
"Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: " + buffer);
Point taskSize = snapshot.getTaskSize();
data.thumbnail = Bitmap.createBitmap(taskSize.x, taskSize.y, ARGB_8888);
data.thumbnail.eraseColor(Color.BLACK);
@@ -0,0 +1,44 @@
package app.lawnchair.compatlib.eleven;
import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.RemoteAnimationAdapter;
import app.lawnchair.compatlib.ActivityOptionsCompat;
public class ActivityOptionsCompatVR extends ActivityOptionsCompat {
private static final String TAG = "ActivityOptionsCompatVR";
@Override
public ActivityOptions makeCustomAnimation(
Context context,
int enterResId,
int exitResId,
Runnable callback,
Handler callbackHandler) {
return ActivityOptions.makeCustomAnimation(
context,
enterResId,
exitResId,
callbackHandler,
new ActivityOptions.OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
if (callback != null) {
callbackHandler.post(callback);
}
}
},
null /* finishedListener */);
}
@Override
public ActivityOptions makeRemoteAnimation(
RemoteAnimationAdapter remoteAnimationAdapter,
Object remoteTransition,
String debugName) {
Log.e(TAG, "makeRemoteAnimation: " + debugName);
return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter);
}
}
@@ -0,0 +1,40 @@
package app.lawnchair.compatlib.eleven;
import android.app.IApplicationThread;
import android.window.IRemoteTransition;
import android.window.RemoteTransition;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.ActivityOptionsCompat;
import app.lawnchair.compatlib.QuickstepCompatFactory;
import app.lawnchair.compatlib.RemoteTransitionCompat;
public class QuickstepCompatFactoryVR extends QuickstepCompatFactory {
@NonNull
@Override
public ActivityManagerCompat getActivityManagerCompat() {
return new ActivityManagerCompatVR();
}
@NonNull
@Override
public ActivityOptionsCompat getActivityOptionsCompat() {
return new ActivityOptionsCompatVR();
}
@NonNull
@Override
public RemoteTransitionCompat getRemoteTransitionCompat() {
return new RemoteTransitionCompat() {
@Override
public RemoteTransition getRemoteTransition(
@NonNull IRemoteTransition remoteTransition,
@Nullable IApplicationThread appThread,
@Nullable String debugName) {
return new RemoteTransition(remoteTransition, appThread, debugName);
}
};
}
}
@@ -0,0 +1,33 @@
package app.lawnchair.compatlib.eleven;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import android.app.WindowConfiguration;
import android.os.RemoteException;
import android.util.Log;
import android.view.WindowManagerGlobal;
public class WindowManagerCompatVR {
public static final int NAV_BAR_POS_INVALID = NAV_BAR_INVALID;
public static final int NAV_BAR_POS_LEFT = NAV_BAR_LEFT;
public static final int NAV_BAR_POS_RIGHT = NAV_BAR_RIGHT;
public static final int NAV_BAR_POS_BOTTOM = NAV_BAR_BOTTOM;
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 int getNavBarPosition(int displayId) {
try {
return WindowManagerGlobal.getWindowManagerService().getNavBarPosition(displayId);
} catch (RemoteException e) {
Log.w("WindowManagerCompatVR", "Failed to get nav bar position");
}
return NAV_BAR_POS_INVALID;
}
}
File renamed without changes.
@@ -0,0 +1,112 @@
package app.lawnchair.compatlib.twelve;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.ActivityTaskManager.getService;
import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.Intent;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.window.TaskSnapshot;
import androidx.annotation.Nullable;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.RecentsAnimationRunnerCompat;
import java.util.List;
public class ActivityManagerCompatVS extends ActivityManagerCompat {
private static final String TAG = "ActivityManagerCompatVS";
private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
@Override
public void invalidateHomeTaskSnapshot(Activity homeActivity) {
try {
ActivityClient.getInstance()
.invalidateHomeTaskSnapshot(
homeActivity == null ? null : homeActivity.getActivityToken());
} catch (Throwable e) {
Log.w(TAG, "Failed to invalidate home snapshot", e);
}
}
@Nullable
@Override
public TaskSnapshot getTaskSnapshot(
int taskId, boolean isLowResolution, boolean takeSnapshotIfNeeded) {
try {
return getService().getTaskSnapshot(taskId, isLowResolution);
} catch (RemoteException e) {
Log.w(TAG, "Failed to getTaskSnapshot", e);
return null;
}
}
@Override
public void startRecentsActivity(
Intent intent, long eventTime, RecentsAnimationRunnerCompat runnerCompat) {
IRecentsAnimationRunner runner = null;
if (runnerCompat != null) {
runner =
new IRecentsAnimationRunner.Stub() {
@Override
public void onAnimationStart(
IRecentsAnimationController controller,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
Rect homeContentInsets,
Rect minimizedHomeBounds) {
runnerCompat.onAnimationStart(
controller,
apps,
wallpapers,
homeContentInsets,
minimizedHomeBounds);
}
@Override
public void onAnimationCanceled(TaskSnapshot taskSnapshot) {
runnerCompat.onAnimationCanceled(taskSnapshot);
}
@Override
public void onTaskAppeared(RemoteAnimationTarget app) {
runnerCompat.onTaskAppeared(app);
}
};
}
try {
getService().startRecentsActivity(intent, eventTime, runner);
} catch (RemoteException e) {
Log.e(TAG, "Failed to cancel recents animation", e);
}
}
@Override
public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
// Note: The set of running tasks from the system is ordered by recency
List<ActivityManager.RunningTaskInfo> tasks = mAtm.getTasks(1, filterOnlyVisibleRecents);
if (tasks.isEmpty()) {
return null;
}
return tasks.get(0);
}
@Override
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
return mAtm.getRecentTasks(numTasks, RECENT_IGNORE_UNAVAILABLE, userId);
}
@Override
public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
List<ActivityManager.RunningTaskInfo> tasks =
mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents);
return tasks.toArray(new ActivityManager.RunningTaskInfo[tasks.size()]);
}
}
@@ -0,0 +1,44 @@
package app.lawnchair.compatlib.twelve;
import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.RemoteAnimationAdapter;
import app.lawnchair.compatlib.ActivityOptionsCompat;
public class ActivityOptionsCompatVS extends ActivityOptionsCompat {
private static final String TAG = "ActivityOptionsCompatVS";
@Override
public ActivityOptions makeCustomAnimation(
Context context,
int enterResId,
int exitResId,
Runnable callback,
Handler callbackHandler) {
return ActivityOptions.makeCustomTaskAnimation(
context,
enterResId,
exitResId,
callbackHandler,
new ActivityOptions.OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
if (callback != null) {
callbackHandler.post(callback);
}
}
},
null /* finishedListener */);
}
@Override
public ActivityOptions makeRemoteAnimation(
RemoteAnimationAdapter remoteAnimationAdapter,
Object remoteTransition,
String debugName) {
Log.e(TAG, "makeRemoteAnimation: " + debugName);
return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter);
}
}
@@ -0,0 +1,60 @@
package app.lawnchair.compatlib.twelve;
import android.app.IApplicationThread;
import android.window.IRemoteTransition;
import android.window.RemoteTransition;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.ActivityOptionsCompat;
import app.lawnchair.compatlib.QuickstepCompatFactory;
import app.lawnchair.compatlib.RemoteTransitionCompat;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class QuickstepCompatFactoryVS extends QuickstepCompatFactory {
@NonNull
@Override
public ActivityManagerCompat getActivityManagerCompat() {
return new ActivityManagerCompatVS();
}
@NonNull
@Override
public ActivityOptionsCompat getActivityOptionsCompat() {
return new ActivityOptionsCompatVS();
}
@NonNull
@Override
public RemoteTransitionCompat getRemoteTransitionCompat() {
return new RemoteTransitionCompat() {
@Override
public RemoteTransition getRemoteTransition(
@NonNull IRemoteTransition remoteTransition,
@Nullable IApplicationThread appThread,
@Nullable String debugName) {
return createRemoteTransition(remoteTransition, appThread, debugName);
}
};
}
// TODO remove this as it causing glitches on first launch opening/closing app
private RemoteTransition createRemoteTransition(
IRemoteTransition remoteTransition, IApplicationThread appThread, String debugName) {
try {
Class<?> remoteTransitionClass = Class.forName("android.window.RemoteTransition");
Constructor<?> constructor =
remoteTransitionClass.getConstructor(
IRemoteTransition.class, IApplicationThread.class, String.class);
return (RemoteTransition) constructor.newInstance(remoteTransition, appThread);
} catch (ClassNotFoundException
| IllegalAccessException
| InstantiationException
| InvocationTargetException
| NoSuchMethodException e) {
throw new RuntimeException("Error creating RemoteTransitionCompat" + debugName, e);
}
}
}
+14
View File
@@ -0,0 +1,14 @@
plugins {
id 'com.android.library'
}
android {
namespace 'app.lawnchair.compatlib.thirteen'
}
addFrameworkJar('framework-13.jar')
dependencies {
implementation projects.compatLib
implementation projects.compatLib.compatLibVS
}
@@ -0,0 +1,78 @@
package app.lawnchair.compatlib.thirteen;
import static android.app.ActivityTaskManager.getService;
import android.app.ActivityTaskManager;
import android.content.Intent;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.window.TaskSnapshot;
import app.lawnchair.compatlib.RecentsAnimationRunnerCompat;
import app.lawnchair.compatlib.twelve.ActivityManagerCompatVS;
public class ActivityManagerCompatVT extends ActivityManagerCompatVS {
private static final String TAG = "ActivityManagerCompatVT";
private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
@Override
public void startRecentsActivity(
Intent intent, long eventTime, RecentsAnimationRunnerCompat runnerCompat) {
IRecentsAnimationRunner runner = null;
if (runnerCompat != null) {
runner =
new IRecentsAnimationRunner.Stub() {
@Override
public void onAnimationStart(
IRecentsAnimationController controller,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
Rect homeContentInsets,
Rect minimizedHomeBounds) {
runnerCompat.onAnimationStart(
controller,
apps,
wallpapers,
homeContentInsets,
minimizedHomeBounds);
}
@Override
public void onAnimationCanceled(
int[] taskIds, TaskSnapshot[] taskSnapshots) {
runnerCompat.onAnimationCanceled(taskIds, taskSnapshots);
}
@Override
public void onTasksAppeared(RemoteAnimationTarget[] apps) {
runnerCompat.onTasksAppeared(apps);
}
};
}
try {
getService().startRecentsActivity(intent, eventTime, runner);
} catch (RemoteException e) {
Log.e(TAG, "Failed to cancel recents animation", e);
}
}
@Override
public TaskSnapshot getTaskSnapshot(
int taskId, boolean isLowResolution, boolean takeSnapshotIfNeeded) {
try {
// android13 qpr1
return getService()
.getTaskSnapshot(taskId, isLowResolution, true /* takeSnapshotIfNeeded */);
} catch (RemoteException e) {
Log.e(TAG, "Failed to getTaskSnapshot", e);
return null;
} catch (NoSuchMethodError e) {
// android13/12
return super.getTaskSnapshot(taskId, isLowResolution, takeSnapshotIfNeeded);
}
}
}
@@ -0,0 +1,34 @@
package app.lawnchair.compatlib.thirteen;
import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.RemoteAnimationAdapter;
import android.window.RemoteTransition;
import app.lawnchair.compatlib.twelve.ActivityOptionsCompatVS;
public class ActivityOptionsCompatVT extends ActivityOptionsCompatVS {
private static final String TAG = "ActivityOptionsCompatVT";
@Override
public ActivityOptions makeCustomAnimation(
Context context,
int enterResId,
int exitResId,
Runnable callback,
Handler callbackHandler) {
return super.makeCustomAnimation(context, enterResId, exitResId, callback, callbackHandler);
}
@Override
public ActivityOptions makeRemoteAnimation(
RemoteAnimationAdapter remoteAnimationAdapter,
Object remoteTransition,
String debugName) {
Log.e(TAG, "makeRemoteAnimation: " + debugName);
return ActivityOptions.makeRemoteAnimation(
remoteAnimationAdapter, (RemoteTransition) remoteTransition);
}
}
@@ -0,0 +1,40 @@
package app.lawnchair.compatlib.thirteen;
import android.app.IApplicationThread;
import android.window.IRemoteTransition;
import android.window.RemoteTransition;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.ActivityOptionsCompat;
import app.lawnchair.compatlib.RemoteTransitionCompat;
import app.lawnchair.compatlib.twelve.QuickstepCompatFactoryVS;
public class QuickstepCompatFactoryVT extends QuickstepCompatFactoryVS {
@NonNull
@Override
public ActivityManagerCompat getActivityManagerCompat() {
return new ActivityManagerCompatVT();
}
@NonNull
@Override
public ActivityOptionsCompat getActivityOptionsCompat() {
return new ActivityOptionsCompatVT();
}
@NonNull
@Override
public RemoteTransitionCompat getRemoteTransitionCompat() {
return new RemoteTransitionCompat() {
@Override
public RemoteTransition getRemoteTransition(
@NonNull IRemoteTransition remoteTransition,
@Nullable IApplicationThread appThread,
@Nullable String debugName) {
return new RemoteTransition(remoteTransition, appThread);
}
};
}
}
+15
View File
@@ -0,0 +1,15 @@
plugins {
id 'com.android.library'
}
android {
namespace 'app.lawnchair.compatlib.fourteen'
}
addFrameworkJar('framework-14.jar')
dependencies {
implementation projects.compatLib
implementation projects.compatLib.compatLibVS
implementation projects.compatLib.compatLibVT
}
@@ -0,0 +1,74 @@
package app.lawnchair.compatlib.fourteen;
import static android.app.ActivityTaskManager.getService;
import android.content.Intent;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.window.TaskSnapshot;
import app.lawnchair.compatlib.RecentsAnimationRunnerCompat;
import app.lawnchair.compatlib.thirteen.ActivityManagerCompatVT;
public class ActivityManagerCompatVU extends ActivityManagerCompatVT {
private static final String TAG = "ActivityManagerCompatVU";
@Override
public void startRecentsActivity(
Intent intent, long eventTime, RecentsAnimationRunnerCompat runnerCompat) {
IRecentsAnimationRunner runner = null;
if (runnerCompat != null) {
runner =
new IRecentsAnimationRunner.Stub() {
@Override
public void onAnimationStart(
IRecentsAnimationController controller,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
Rect homeContentInsets,
Rect minimizedHomeBounds) {
runnerCompat.onAnimationStart(
controller,
apps,
wallpapers,
homeContentInsets,
minimizedHomeBounds);
}
@Override
public void onAnimationCanceled(
int[] taskIds, TaskSnapshot[] taskSnapshots) {
runnerCompat.onAnimationCanceled(taskIds, taskSnapshots);
}
@Override
public void onTasksAppeared(RemoteAnimationTarget[] apps) {
runnerCompat.onTasksAppeared(apps);
}
};
}
try {
getService().startRecentsActivity(intent, eventTime, runner);
} catch (RemoteException e) {
Log.e(TAG, "Failed to cancel recents animation", e);
}
}
@Override
public TaskSnapshot getTaskSnapshot(
int taskId, boolean isLowResolution, boolean takeSnapshotIfNeeded) {
try {
return getService()
.getTaskSnapshot(taskId, isLowResolution, true /* takeSnapshotIfNeeded */);
} catch (RemoteException e) {
Log.e(TAG, "Failed to getTaskSnapshot", e);
return null;
} catch (NoSuchMethodError e) {
return super.getTaskSnapshot(taskId, isLowResolution, takeSnapshotIfNeeded);
}
}
}
@@ -0,0 +1,29 @@
package app.lawnchair.compatlib.fourteen;
import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
import android.view.RemoteAnimationAdapter;
import android.window.RemoteTransition;
import app.lawnchair.compatlib.ActivityOptionsCompat;
public class ActivityOptionsCompatVU extends ActivityOptionsCompat {
@Override
public ActivityOptions makeCustomAnimation(
Context context,
int enterResId,
int exitResId,
Runnable callback,
Handler callbackHandler) {
return null;
}
@Override
public ActivityOptions makeRemoteAnimation(
RemoteAnimationAdapter remoteAnimationAdapter,
Object remoteTransition,
String debugName) {
return ActivityOptions.makeRemoteAnimation(
remoteAnimationAdapter, (RemoteTransition) remoteTransition);
}
}
@@ -0,0 +1,40 @@
package app.lawnchair.compatlib.fourteen;
import android.app.IApplicationThread;
import android.window.IRemoteTransition;
import android.window.RemoteTransition;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.ActivityOptionsCompat;
import app.lawnchair.compatlib.RemoteTransitionCompat;
import app.lawnchair.compatlib.thirteen.QuickstepCompatFactoryVT;
public class QuickstepCompatFactoryVU extends QuickstepCompatFactoryVT {
@NonNull
@Override
public ActivityManagerCompat getActivityManagerCompat() {
return new ActivityManagerCompatVU();
}
@NonNull
@Override
public ActivityOptionsCompat getActivityOptionsCompat() {
return new ActivityOptionsCompatVU();
}
@NonNull
@Override
public RemoteTransitionCompat getRemoteTransitionCompat() {
return new RemoteTransitionCompat() {
@Override
public RemoteTransition getRemoteTransition(
@NonNull IRemoteTransition remoteTransition,
@Nullable IApplicationThread appThread,
@Nullable String debugName) {
return new RemoteTransition(remoteTransition, appThread, debugName);
}
};
}
}
@@ -0,0 +1,62 @@
/*
* 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 android.window;
import android.view.SurfaceControl;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.TransitionInfo;
/**
* Interface allowing remote processes to play transition animations.
* The usage flow is as follows:
* <p><ol>
* <li>The remote tags a lifecycle event with an IRemoteTransition (via a parameter in
* ActivityOptions#makeRemoteAnimation) or a transition matches a filter registered via
* Transitions#registerRemote.
* <li>Shell then associates the transition for the event with the IRemoteTransition
* <li>Shell receives onTransitionReady and delegates the animation to the IRemoteTransition
* via {@link #startAnimation}.
* <li>Once the IRemoteTransition is done animating, it will call the finishCallback.
* <li>Shell/Core finish-up the transition.
* </ul>
*
* {@hide}
*/
oneway interface IRemoteTransition {
/**
* Starts a transition animation. Once complete, the implementation should call
* `finishCallback`.
*
* @param token An identifier for the transition that should be animated.
*/
void startAnimation(in IBinder token, in TransitionInfo info, in SurfaceControl.Transaction t,
in IRemoteTransitionFinishedCallback finishCallback);
/**
* Attempts to merge a transition animation into the animation that is currently
* being played by this remote. If merge is not possible/supported, this should be a no-op.
* If it *is* merged, the implementation should call `finishCallback` immediately.
*
* @param transition An identifier for the transition that wants to be merged.
* @param mergeTarget The transition that is currently being animated by this remote.
* If it can be merged, call `finishCallback`; otherwise, do
* nothing.
*/
void mergeAnimation(in IBinder transition, in TransitionInfo info,
in SurfaceControl.Transaction t, in IBinder mergeTarget,
in IRemoteTransitionFinishedCallback finishCallback);
}
@@ -0,0 +1,30 @@
/*
* 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 android.window;
import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
/**
* Interface to be invoked by the controlling process when a remote transition has finished.
*
* @see IRemoteTransition
* @param wct An optional WindowContainerTransaction to apply before the transition finished.
* @param sct An optional Surface Transaction that is added to the end of the finish/cleanup
* transaction. This is applied by shell.Transitions (before submitting the wct).
* {@hide}
*/
interface IRemoteTransitionFinishedCallback {
void onTransitionFinished(in WindowContainerTransaction wct, in SurfaceControl.Transaction sct);
}
@@ -0,0 +1,19 @@
/*
* 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 android.window;
parcelable RemoteTransition;
@@ -0,0 +1,199 @@
package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.IApplicationThread;
import android.os.IBinder;
import android.os.Parcelable;
import com.android.internal.util.DataClass;
/**
* Represents a remote transition animation and information required to run it (eg. the app thread
* that needs to be boosted).
*
* @hide
*/
@DataClass(genToString = true, genSetters = true, genAidl = true)
public class RemoteTransition implements Parcelable {
/** The actual remote-transition interface used to run the transition animation. */
private @NonNull IRemoteTransition mRemoteTransition;
/** The application thread that will be running the remote transition. */
private @Nullable IApplicationThread mAppThread;
/** A name for this that can be used for debugging. */
private @Nullable String mDebugName;
/** Constructs with no app thread (animation runs in shell). */
public RemoteTransition(@NonNull IRemoteTransition remoteTransition) {
this(remoteTransition, null /* appThread */, null /* debugName */);
}
/** Constructs with no app thread (animation runs in shell). */
public RemoteTransition(
@NonNull IRemoteTransition remoteTransition, @Nullable String debugName) {
this(remoteTransition, null /* appThread */, debugName);
}
/** Get the IBinder associated with the underlying IRemoteTransition. */
public @Nullable IBinder asBinder() {
return mRemoteTransition.asBinder();
}
// Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/window/RemoteTransition.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
// @formatter:off
/**
* Creates a new RemoteTransition.
*
* @param remoteTransition The actual remote-transition interface used to run the transition
* animation.
* @param appThread The application thread that will be running the remote transition.
* @param debugName A name for this that can be used for debugging.
*/
@DataClass.Generated.Member
public RemoteTransition(
@NonNull IRemoteTransition remoteTransition,
@Nullable IApplicationThread appThread,
@Nullable String debugName) {
this.mRemoteTransition = remoteTransition;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mRemoteTransition);
this.mAppThread = appThread;
this.mDebugName = debugName;
// onConstructed(); // You can define this method to get a callback
}
/** The actual remote-transition interface used to run the transition animation. */
@DataClass.Generated.Member
public @NonNull IRemoteTransition getRemoteTransition() {
return mRemoteTransition;
}
/** The application thread that will be running the remote transition. */
@DataClass.Generated.Member
public @Nullable IApplicationThread getAppThread() {
return mAppThread;
}
/** A name for this that can be used for debugging. */
@DataClass.Generated.Member
public @Nullable String getDebugName() {
return mDebugName;
}
/** The actual remote-transition interface used to run the transition animation. */
@DataClass.Generated.Member
public @NonNull RemoteTransition setRemoteTransition(@NonNull IRemoteTransition value) {
mRemoteTransition = value;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mRemoteTransition);
return this;
}
/** The application thread that will be running the remote transition. */
@DataClass.Generated.Member
public @NonNull RemoteTransition setAppThread(@NonNull IApplicationThread value) {
mAppThread = value;
return this;
}
/** A name for this that can be used for debugging. */
@DataClass.Generated.Member
public @NonNull RemoteTransition setDebugName(@NonNull String value) {
mDebugName = value;
return this;
}
@Override
@DataClass.Generated.Member
public String toString() {
// You can override field toString logic by defining methods like:
// String fieldNameToString() { ... }
return "RemoteTransition { "
+ "remoteTransition = "
+ mRemoteTransition
+ ", "
+ "appThread = "
+ mAppThread
+ ", "
+ "debugName = "
+ mDebugName
+ " }";
}
@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 (mAppThread != null) flg |= 0x2;
if (mDebugName != null) flg |= 0x4;
dest.writeByte(flg);
dest.writeStrongInterface(mRemoteTransition);
if (mAppThread != null) dest.writeStrongInterface(mAppThread);
if (mDebugName != null) dest.writeString(mDebugName);
}
@Override
@DataClass.Generated.Member
public int describeContents() {
return 0;
}
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
protected RemoteTransition(@NonNull android.os.Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
IRemoteTransition remoteTransition =
IRemoteTransition.Stub.asInterface(in.readStrongBinder());
IApplicationThread appThread =
(flg & 0x2) == 0
? null
: IApplicationThread.Stub.asInterface(in.readStrongBinder());
String debugName = (flg & 0x4) == 0 ? null : in.readString();
this.mRemoteTransition = remoteTransition;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mRemoteTransition);
this.mAppThread = appThread;
this.mDebugName = debugName;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<RemoteTransition> CREATOR =
new Parcelable.Creator<RemoteTransition>() {
@Override
public RemoteTransition[] newArray(int size) {
return new RemoteTransition[size];
}
@Override
public RemoteTransition createFromParcel(@NonNull android.os.Parcel in) {
return new RemoteTransition(in);
}
};
@DataClass.Generated(
time = 1678926409863L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/window/RemoteTransition.java",
inputSignatures =
"private @android.annotation.NonNull android.window.IRemoteTransition mRemoteTransition\nprivate @android.annotation.Nullable android.app.IApplicationThread mAppThread\nprivate @android.annotation.Nullable java.lang.String mDebugName\npublic @android.annotation.Nullable android.os.IBinder asBinder()\nclass RemoteTransition extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
@Deprecated
private void __metadata() {}
// @formatter:on
// End of generated code
}
@@ -0,0 +1,19 @@
/*
* 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 android.window;
parcelable TransitionFilter;
@@ -0,0 +1,316 @@
/*
* 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 android.window;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.view.WindowManager.TransitionType;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.WindowManager;
/**
* A parcelable filter that can be used for rerouting transitions to a remote. This is a local
* representation so that the transition system doesn't need to make blocking queries over binder.
*
* @hide
*/
public final class TransitionFilter implements Parcelable {
/** The associated requirement doesn't care about the z-order. */
public static final int CONTAINER_ORDER_ANY = 0;
/** The associated requirement only matches the top-most (z-order) container. */
public static final int CONTAINER_ORDER_TOP = 1;
/** @hide */
@IntDef(
prefix = {"CONTAINER_ORDER_"},
value = {
CONTAINER_ORDER_ANY,
CONTAINER_ORDER_TOP,
})
public @interface ContainerOrder {}
/**
* When non-null: this is a list of transition types that this filter applies to. This filter
* will fail for transitions that aren't one of these types.
*/
@Nullable public @TransitionType int[] mTypeSet = null;
/** All flags must be set on a transition. */
public @WindowManager.TransitionFlags int mFlags = 0;
/** All flags must NOT be set on a transition. */
public @WindowManager.TransitionFlags int mNotFlags = 0;
/** A list of required changes. To pass, a transition must meet all requirements. */
@Nullable public Requirement[] mRequirements = null;
public TransitionFilter() {}
private TransitionFilter(Parcel in) {
mTypeSet = in.createIntArray();
mFlags = in.readInt();
mNotFlags = in.readInt();
mRequirements = in.createTypedArray(Requirement.CREATOR);
}
/**
* @return true if `info` meets all the requirements to pass this filter.
*/
public boolean matches(@NonNull TransitionInfo info) {
if (mTypeSet != null) {
// non-null typeset, so make sure info is one of the types.
boolean typePass = false;
for (int i = 0; i < mTypeSet.length; ++i) {
if (info.getType() == mTypeSet[i]) {
typePass = true;
break;
}
}
if (!typePass) return false;
}
if ((info.getFlags() & mFlags) != mFlags) {
return false;
}
if ((info.getFlags() & mNotFlags) != 0) {
return false;
}
// Make sure info meets all of the requirements.
if (mRequirements != null) {
for (int i = 0; i < mRequirements.length; ++i) {
final boolean matches = mRequirements[i].matches(info);
if (matches == mRequirements[i].mNot) {
return false;
}
}
}
return true;
}
@Override
/** @hide */
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeIntArray(mTypeSet);
dest.writeInt(mFlags);
dest.writeInt(mNotFlags);
dest.writeTypedArray(mRequirements, flags);
}
@NonNull
public static final Creator<TransitionFilter> CREATOR =
new Creator<TransitionFilter>() {
@Override
public TransitionFilter createFromParcel(Parcel in) {
return new TransitionFilter(in);
}
@Override
public TransitionFilter[] newArray(int size) {
return new TransitionFilter[size];
}
};
@Override
/** @hide */
public int describeContents() {
return 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{types=[");
if (mTypeSet != null) {
for (int i = 0; i < mTypeSet.length; ++i) {
sb.append((i == 0 ? "" : ",") + WindowManager.transitTypeToString(mTypeSet[i]));
}
}
sb.append("] flags=0x" + Integer.toHexString(mFlags));
sb.append("] notFlags=0x" + Integer.toHexString(mNotFlags));
sb.append(" checks=[");
if (mRequirements != null) {
for (int i = 0; i < mRequirements.length; ++i) {
sb.append((i == 0 ? "" : ",") + mRequirements[i]);
}
}
return sb.append("]}").toString();
}
/**
* Matches a change that a transition must contain to pass this filter. All requirements in a
* filter must be met to pass the filter.
*/
public static final class Requirement implements Parcelable {
public int mActivityType = ACTIVITY_TYPE_UNDEFINED;
/** This only matches if the change is independent of its parents. */
public boolean mMustBeIndependent = true;
/** If this matches, the parent filter will fail */
public boolean mNot = false;
public int[] mModes = null;
/** Matches only if all the flags here are set on the change. */
public @TransitionInfo.ChangeFlags int mFlags = 0;
/** If this needs to be a task. */
public boolean mMustBeTask = false;
public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY;
public ComponentName mTopActivity;
public Requirement() {}
private Requirement(Parcel in) {
mActivityType = in.readInt();
mMustBeIndependent = in.readBoolean();
mNot = in.readBoolean();
mModes = in.createIntArray();
mFlags = in.readInt();
mMustBeTask = in.readBoolean();
mOrder = in.readInt();
mTopActivity = in.readTypedObject(ComponentName.CREATOR);
}
/** Go through changes and find if at-least one change matches this filter */
boolean matches(@NonNull TransitionInfo info) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (mMustBeIndependent && !TransitionInfo.isIndependent(change, info)) {
// Only look at independent animating windows.
continue;
}
if (mOrder == CONTAINER_ORDER_TOP && i > 0) {
continue;
}
if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
if (change.getTaskInfo() == null
|| change.getTaskInfo().getActivityType() != mActivityType) {
continue;
}
}
if (!matchesTopActivity(change.getTaskInfo())) continue;
if (mModes != null) {
boolean pass = false;
for (int m = 0; m < mModes.length; ++m) {
if (mModes[m] == change.getMode()) {
pass = true;
break;
}
}
if (!pass) continue;
}
if ((change.getFlags() & mFlags) != mFlags) {
continue;
}
if (mMustBeTask && change.getTaskInfo() == null) {
continue;
}
return true;
}
return false;
}
private boolean matchesTopActivity(ActivityManager.RunningTaskInfo info) {
if (mTopActivity == null) return true;
if (info == null) return false;
final ComponentName component = info.topActivity;
return mTopActivity.equals(component);
}
/** Check if the request matches this filter. It may generate false positives */
boolean matches(@NonNull TransitionRequestInfo request) {
// Can't check modes/order since the transition hasn't been built at this point.
if (mActivityType == ACTIVITY_TYPE_UNDEFINED) return true;
return request.getTriggerTask() != null
&& request.getTriggerTask().getActivityType() == mActivityType
&& matchesTopActivity(request.getTriggerTask());
}
@Override
/** @hide */
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mActivityType);
dest.writeBoolean(mMustBeIndependent);
dest.writeBoolean(mNot);
dest.writeIntArray(mModes);
dest.writeInt(mFlags);
dest.writeBoolean(mMustBeTask);
dest.writeInt(mOrder);
dest.writeTypedObject(mTopActivity, flags);
}
@NonNull
public static final Creator<Requirement> CREATOR =
new Creator<Requirement>() {
@Override
public Requirement createFromParcel(Parcel in) {
return new Requirement(in);
}
@Override
public Requirement[] newArray(int size) {
return new Requirement[size];
}
};
@Override
/** @hide */
public int describeContents() {
return 0;
}
@Override
public String toString() {
StringBuilder out = new StringBuilder();
out.append('{');
if (mNot) out.append("NOT ");
out.append("atype=" + WindowConfiguration.activityTypeToString(mActivityType));
out.append(" independent=" + mMustBeIndependent);
out.append(" modes=[");
if (mModes != null) {
for (int i = 0; i < mModes.length; ++i) {
out.append((i == 0 ? "" : ",") + TransitionInfo.modeToString(mModes[i]));
}
}
out.append("]");
out.append(" flags=" + TransitionInfo.flagsToString(mFlags));
out.append(" mustBeTask=" + mMustBeTask);
out.append(" order=" + containerOrderToString(mOrder));
out.append(" topActivity=").append(mTopActivity);
out.append("}");
return out.toString();
}
}
private static String containerOrderToString(int order) {
switch (order) {
case CONTAINER_ORDER_ANY:
return "ANY";
case CONTAINER_ORDER_TOP:
return "TOP";
}
return "UNKNOWN(" + order + ")";
}
}
@@ -0,0 +1,18 @@
/*
* 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 android.window;
parcelable TransitionInfo;
parcelable TransitionInfo.Change;
File diff suppressed because it is too large. Load diff
@@ -1,17 +1,40 @@
package app.lawnchair.compatlib;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Intent;
import android.os.RemoteException;
import android.view.IRecentsAnimationRunner;
import android.window.TaskSnapshot;
import androidx.annotation.Nullable;
import java.util.List;
public abstract class ActivityManagerCompat {
public abstract void startRecentsActivity(Intent intent, long eventTime, RecentsAnimationRunnerStub runner) throws RemoteException;
public static final int NUM_RECENT_ACTIVITIES_REQUEST = 3;
public abstract ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents);
public abstract void invalidateHomeTaskSnapshot(final Activity homeActivity);
/**
* Called only in S+ platform
*
* @param taskId
* @param isLowResolution
* @param takeSnapshotIfNeeded
* @return
*/
@Nullable
public TaskSnapshot getTaskSnapshot(
int taskId, boolean isLowResolution, boolean takeSnapshotIfNeeded) {
return null;
}
public abstract void startRecentsActivity(
Intent intent, long eventTime, RecentsAnimationRunnerCompat runnerCompat);
public abstract ActivityManager.RunningTaskInfo getRunningTask(
boolean filterOnlyVisibleRecents);
public abstract List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId);
public abstract ActivityManager.RunningTaskInfo[] getRunningTasks(
boolean filterOnlyVisibleRecents);
}
@@ -0,0 +1,20 @@
package app.lawnchair.compatlib;
import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
import android.view.RemoteAnimationAdapter;
public abstract class ActivityOptionsCompat {
public abstract ActivityOptions makeCustomAnimation(
Context context,
int enterResId,
int exitResId,
final Runnable callback,
final Handler callbackHandler);
public abstract ActivityOptions makeRemoteAnimation(
RemoteAnimationAdapter remoteAnimationAdapter,
Object remoteTransition,
String debugName);
}
@@ -1,10 +1,5 @@
package app.lawnchair.compatlib;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.view.AppTransitionAnimationSpec;
import android.view.IRemoteAnimationRunner;
import androidx.annotation.NonNull;
public abstract class QuickstepCompatFactory {
@@ -12,7 +7,9 @@ public abstract class QuickstepCompatFactory {
@NonNull
public abstract ActivityManagerCompat getActivityManagerCompat();
public abstract IRemoteAnimationRunner.Stub wrapRemoteAnimationRunnerStub(RemoteAnimationRunnerStub compatStub);
@NonNull
public abstract ActivityOptionsCompat getActivityOptionsCompat();
public abstract AppTransitionAnimationSpec createAppTransitionAnimationSpec(int taskId, Bitmap buffer, Rect rect);
@NonNull
public abstract RemoteTransitionCompat getRemoteTransitionCompat();
}
@@ -0,0 +1,28 @@
package app.lawnchair.compatlib;
import android.graphics.Rect;
import android.view.IRecentsAnimationController;
import android.view.RemoteAnimationTarget;
import android.window.TaskSnapshot;
public interface RecentsAnimationRunnerCompat {
void onAnimationStart(
IRecentsAnimationController controller,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
Rect homeContentInsets,
Rect minimizedHomeBounds);
/** Called only in T platform */
void onAnimationCanceled(int[] taskIds, TaskSnapshot[] taskSnapshots);
/** Called only in Q/R/S platform */
void onAnimationCanceled(Object taskSnapshot);
/** Called only in R/S platform */
void onTaskAppeared(RemoteAnimationTarget app);
/** Called only in T+ platform */
void onTasksAppeared(RemoteAnimationTarget[] apps);
}
@@ -1,15 +0,0 @@
package app.lawnchair.compatlib;
import android.graphics.Rect;
import android.view.IRecentsAnimationController;
import android.view.RemoteAnimationTarget;
public interface RecentsAnimationRunnerStub {
void onAnimationStart(IRecentsAnimationController controller,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
Rect homeContentInsets, Rect minimizedHomeBounds);
void onAnimationCanceled(Object taskSnapshot);
void onTaskAppeared(RemoteAnimationTarget app);
}
@@ -1,13 +0,0 @@
package app.lawnchair.compatlib;
import android.view.RemoteAnimationTarget;
import android.view.IRemoteAnimationFinishedCallback;
public interface RemoteAnimationRunnerStub {
void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback);
void onAnimationCancelled();
}
@@ -0,0 +1,15 @@
package app.lawnchair.compatlib;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.IApplicationThread;
import android.window.IRemoteTransition;
import android.window.RemoteTransition;
public abstract class RemoteTransitionCompat {
public abstract RemoteTransition getRemoteTransition(
@NonNull IRemoteTransition remoteTransition,
@Nullable IApplicationThread appThread,
@Nullable String debugName);
}
@@ -1,31 +0,0 @@
package app.lawnchair.compatlib;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.TransitionInfo;
public interface RemoteTransitionStub {
/**
* Starts a transition animation. Once complete, the implementation should call
* `finishCallback`.
*
* @param token An identifier for the transition that should be animated.
*/
void startAnimation(IBinder token, TransitionInfo info, SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishCallback);
/**
* Attempts to merge a transition animation into the animation that is currently
* being played by this remote. If merge is not possible/supported, this should be a no-op.
* If it *is* merged, the implementation should call `finishCallback` immediately.
*
* @param transition An identifier for the transition that wants to be merged.
* @param mergeTarget The transition that is currently being animated by this remote.
* If it can be merged, call `finishCallback`; otherwise, do
* nothing.
*/
void mergeAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget,
IRemoteTransitionFinishedCallback finishCallback);
}
@@ -1,4 +0,0 @@
package app.lawnchair.compatlib;
public class TaskSnapshotCompat {
}
@@ -0,0 +1,80 @@
/*
* 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 app.lawnchair.compatlib.utils;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.ParcelableColorSpace;
import android.hardware.HardwareBuffer;
import android.os.Bundle;
import java.util.Objects;
/** Utils for working with Bitmaps. */
public final class BitmapUtil {
private static final String KEY_BUFFER = "bitmap_util_buffer";
private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
private BitmapUtil() {}
/**
* Creates a Bundle that represents the given Bitmap.
*
* <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
* copies when passing across processes, only pass to processes you trust.
*
* <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
* returned Bundle should be treated as a standalone object.
*
* @param bitmap to convert to bundle
* @return a Bundle representing the bitmap, should only be parsed by {@link
* #bundleToHardwareBitmap(Bundle)}
*/
public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
throw new IllegalArgumentException(
"Passed bitmap must have hardware config, found: " + bitmap.getConfig());
}
// Bitmap assumes SRGB for null color space
ParcelableColorSpace colorSpace =
bitmap.getColorSpace() == null
? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
: new ParcelableColorSpace(bitmap.getColorSpace());
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
return bundle;
}
/**
* Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
*
* <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing this
* Bitmap on to any other source.
*
* @param bundle containing the bitmap
* @return a hardware Bitmap
*/
public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
}
HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
return Bitmap.wrapHardwareBuffer(
Objects.requireNonNull(buffer), colorSpace.getColorSpace());
}
}
@@ -1,47 +0,0 @@
package app.lawnchair.compatlib.eleven;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.RemoteException;
import android.view.AppTransitionAnimationSpec;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
import androidx.annotation.NonNull;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.QuickstepCompatFactory;
import app.lawnchair.compatlib.RemoteAnimationRunnerStub;
public class QuickstepCompatFactoryVR extends QuickstepCompatFactory {
@NonNull
@Override
public ActivityManagerCompat getActivityManagerCompat() {
return new ActivityManagerCompatVR();
}
@Override
public IRemoteAnimationRunner.Stub wrapRemoteAnimationRunnerStub(RemoteAnimationRunnerStub compatStub) {
return new IRemoteAnimationRunner.Stub() {
@Override
public void onAnimationStart(RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
final IRemoteAnimationFinishedCallback finishedCallback) {
compatStub.onAnimationStart(0 /* transit */, apps, wallpapers, null, finishedCallback);
}
@Override
public void onAnimationCancelled() {
compatStub.onAnimationCancelled();
}
};
}
@Override
public AppTransitionAnimationSpec createAppTransitionAnimationSpec(int taskId, Bitmap buffer, Rect rect) {
return new AppTransitionAnimationSpec(taskId,
buffer != null ? buffer.createGraphicBufferHandle() : null, rect);
}
}
@@ -1,66 +0,0 @@
package app.lawnchair.compatlib.twelve;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.ActivityTaskManager.getService;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.Intent;
import android.graphics.Rect;
import android.os.RemoteException;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.window.TaskSnapshot;
import java.util.List;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.RecentsAnimationRunnerStub;
public class ActivityManagerCompatVS extends ActivityManagerCompat {
private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
@Override
public void startRecentsActivity(Intent intent, long eventTime, RecentsAnimationRunnerStub runner) throws RemoteException {
IRecentsAnimationRunner wrappedRunner = null;
if (runner != null) {
wrappedRunner = new IRecentsAnimationRunner.Stub() {
@Override
public void onAnimationStart(IRecentsAnimationController controller,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
Rect homeContentInsets, Rect minimizedHomeBounds) {
runner.onAnimationStart(controller, apps, wallpapers, homeContentInsets, minimizedHomeBounds);
}
@Override
public void onAnimationCanceled(TaskSnapshot taskSnapshot) {
runner.onAnimationCanceled(taskSnapshot);
}
@Override
public void onTaskAppeared(RemoteAnimationTarget app) {
runner.onTaskAppeared(app);
}
};
}
getService().startRecentsActivity(intent, eventTime, wrappedRunner);
}
@Override
public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
// Note: The set of running tasks from the system is ordered by recency
List<ActivityManager.RunningTaskInfo> tasks =
mAtm.getTasks(1, filterOnlyVisibleRecents);
if (tasks.isEmpty()) {
return null;
}
return tasks.get(0);
}
@Override
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
return mAtm.getRecentTasks(numTasks, RECENT_IGNORE_UNAVAILABLE, userId);
}
}
@@ -1,55 +0,0 @@
package app.lawnchair.compatlib.twelve;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.AppTransitionAnimationSpec;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import app.lawnchair.compatlib.ActivityManagerCompat;
import app.lawnchair.compatlib.QuickstepCompatFactory;
import app.lawnchair.compatlib.RemoteAnimationRunnerStub;
import app.lawnchair.compatlib.RemoteTransitionStub;
public class QuickstepCompatFactoryVS extends QuickstepCompatFactory {
@NonNull
@Override
public ActivityManagerCompat getActivityManagerCompat() {
return new ActivityManagerCompatVS();
}
@Override
public IRemoteAnimationRunner.Stub wrapRemoteAnimationRunnerStub(RemoteAnimationRunnerStub compatStub) {
return new IRemoteAnimationRunner.Stub() {
@Override
public void onAnimationStart(int transit,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
compatStub.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback);
}
@Override
public void onAnimationCancelled() {
compatStub.onAnimationCancelled();
}
};
}
@Override
public AppTransitionAnimationSpec createAppTransitionAnimationSpec(int taskId, Bitmap buffer, Rect rect) {
return new AppTransitionAnimationSpec(taskId,
buffer != null ? buffer.getHardwareBuffer() : null, rect);
}
}
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="taskbar_size">60dp</dimen>
</resources>
@@ -21,9 +21,12 @@ import android.content.Context
import android.content.Intent
import android.content.IntentSender
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.Display
import android.view.View
import android.view.ViewTreeObserver
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.OnBackPressedDispatcherOwner
@@ -46,6 +49,7 @@ import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
import app.lawnchair.LawnchairApp.Companion.showQuickstepWarningIfNecessary
import app.lawnchair.compat.LawnchairQuickstepCompat
import app.lawnchair.factory.LawnchairWidgetHolder
import app.lawnchair.gestures.GestureController
import app.lawnchair.gestures.VerticalSwipeTouchController
@@ -61,11 +65,13 @@ import app.lawnchair.util.getThemedIconPacksInstalled
import app.lawnchair.util.unsafeLazy
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.BaseActivity
import com.android.launcher3.BubbleTextView
import com.android.launcher3.GestureNavContract
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherState
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.popup.SystemShortcut
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.uioverrides.QuickstepLauncher
@@ -342,9 +348,9 @@ class LawnchairLauncher :
override fun makeDefaultActivityOptions(splashScreenStyle: Int): ActivityOptionsWrapper {
val callbacks = RunnableList()
val options = if (Utilities.ATLEAST_P || Utilities.ATLEAST_Q) {
val options = if (!Utilities.ATLEAST_R) {
ActivityOptions.makeBasic()
} else {
} else if (Utilities.ATLEAST_T) {
ActivityOptions.makeCustomAnimation(
this,
0,
@@ -353,6 +359,9 @@ class LawnchairLauncher :
Executors.MAIN_EXECUTOR.handler,
null,
) { _ -> callbacks.executeAllAndDestroy() }
} else {
LawnchairQuickstepCompat.activityOptionsCompat
.makeCustomAnimation(this, 0, 0, null, Executors.MAIN_EXECUTOR.handler)
}
if (Utilities.ATLEAST_T) {
options.setSplashScreenStyle(splashScreenStyle)
@@ -362,6 +371,46 @@ class LawnchairLauncher :
return ActivityOptionsWrapper(options, callbacks)
}
override fun getActivityLaunchOptions(v: View?, item: ItemInfo?): ActivityOptionsWrapper {
return runCatching {
super.getActivityLaunchOptions(v, item)
}.getOrElse {
getActivityLaunchOptionsDefault(v, item)
}
}
private fun getActivityLaunchOptionsDefault(v: View?, item: ItemInfo?): ActivityOptionsWrapper {
var left = 0
var top = 0
var width = v!!.measuredWidth
var height = v.measuredHeight
if (v is BubbleTextView) {
// Launch from center of icon, not entire view
val icon: Drawable? = v.icon
if (icon != null) {
val bounds = icon.bounds
left = (width - bounds.width()) / 2
top = v.getPaddingTop()
width = bounds.width()
height = bounds.height()
}
}
val options = Utilities.allowBGLaunch(
ActivityOptions.makeClipRevealAnimation(
v,
left,
top,
width,
height,
),
)
options.setLaunchDisplayId(
if (v != null && v.display != null) v.display.displayId else Display.DEFAULT_DISPLAY,
)
val callback = RunnableList()
return ActivityOptionsWrapper(options, callback)
}
override fun onStart() {
super.onStart()
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START)
@@ -13,6 +13,7 @@ import android.text.style.ForegroundColorSpan
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.View
import android.view.View.OnFocusChangeListener
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import android.widget.ImageButton
@@ -33,7 +34,6 @@ import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.allapps.ActivityAllAppsContainerView
import com.android.launcher3.allapps.AllAppsStore
import com.android.launcher3.allapps.AlphabeticalAppsList
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem
import com.android.launcher3.allapps.SearchUiManager
import com.android.launcher3.allapps.search.AllAppsSearchBarController
@@ -64,7 +64,7 @@ class AllAppsSearchInput(context: Context, attrs: AttributeSet?) :
Selection.setSelection(this, 0)
}
private lateinit var apps: AlphabeticalAppsList<*>
private lateinit var apps: LawnchairAlphabeticalAppsList<*>
private lateinit var appsView: ActivityAllAppsContainerView<*>
private var focusedResultTitle = ""
@@ -192,7 +192,7 @@ class AllAppsSearchInput(context: Context, attrs: AttributeSet?) :
}
override fun initializeSearch(appsView: ActivityAllAppsContainerView<*>) {
apps = appsView.searchResultList
apps = appsView.searchResultList as LawnchairAlphabeticalAppsList<*>
this.appsView = appsView
searchBarController.initialize(
LawnchairSearchAlgorithm.create(context),
@@ -1,6 +1,7 @@
package app.lawnchair.allapps
import android.content.Context
import android.util.Log
import androidx.lifecycle.lifecycleScope
import app.lawnchair.launcher
import app.lawnchair.preferences2.PreferenceManager2
@@ -21,12 +22,16 @@ class LawnchairAlphabeticalAppsList<T>(
where T : Context, T : ActivityContext {
private var hiddenApps: Set<String> = setOf()
private val prefs = PreferenceManager2.getInstance(context)
init {
val prefs = PreferenceManager2.getInstance(context)
prefs.hiddenApps.onEach(launchIn = context.launcher.lifecycleScope) {
hiddenApps = it
onAppsUpdated()
try {
prefs.hiddenApps.onEach(launchIn = context.launcher.lifecycleScope) {
hiddenApps = it
onAppsUpdated()
}
} catch (t: Throwable) {
Log.w(TAG, "Failed initialize ignore: ", t)
}
}
@@ -0,0 +1,156 @@
package app.lawnchair.overview
import android.app.ActivityOptions
import android.graphics.Color
import android.graphics.Rect
import android.os.Handler
import android.os.Looper
import android.os.RemoteException
import android.util.Log
import android.view.Display
import android.view.View
import android.view.WindowManagerGlobal
import app.lawnchair.compat.LawnchairQuickstepCompat
import app.lawnchair.compatlib.eleven.WindowManagerCompatVR
import com.android.launcher3.BaseDraggingActivity
import com.android.launcher3.R
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.popup.SystemShortcut
import com.android.quickstep.TaskShortcutFactory
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.TaskThumbnailView
import com.android.quickstep.views.TaskView
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture
import com.android.systemui.shared.recents.view.RecentsTransition
import com.android.systemui.shared.system.ActivityManagerWrapper
object TaskShortcutFactory {
class LegacySplitSystemShortcut(
iconRes: Int,
textRes: Int,
activity: BaseDraggingActivity,
taskContainer: TaskIdAttributeContainer,
private val mLauncherEvent: LauncherEvent,
) : SystemShortcut<BaseDraggingActivity?>(
iconRes,
textRes,
activity,
taskContainer.itemInfo,
taskContainer.taskView,
) {
private val mHandler: Handler = Handler(Looper.getMainLooper())
private val mRecentsView: RecentsView<*, *> = activity.getOverviewPanel()
private val mThumbnailView: TaskThumbnailView = taskContainer.thumbnailView
private val mTaskView: TaskView = taskContainer.taskView
private fun makeLaunchOptions(activity: BaseDraggingActivity): ActivityOptions? {
val navBarPosition: Int = WindowManagerCompatVR.getNavBarPosition(activity.displayId)
if (navBarPosition == WindowManagerCompatVR.NAV_BAR_POS_INVALID) {
return null
}
val options = ActivityOptions.makeBasic()
options.launchWindowingMode = WindowManagerCompatVR.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
return options
}
override fun onClick(view: View) {
val taskKey = mTaskView.task!!.key
val taskId = taskKey.id
dismissTaskMenuView(mTarget)
val options = makeLaunchOptions(mTarget!!)
if (options != null && ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId, options)) {
val animStartedListener =
Runnable { mRecentsView.dismissTask(mTaskView, false, false) }
val position = IntArray(2)
mThumbnailView.getLocationOnScreen(position)
val width = (mThumbnailView.width * mTaskView.scaleX).toInt()
val height = (mThumbnailView.height * mTaskView.scaleY).toInt()
val taskBounds = Rect(
position[0],
position[1],
position[0] + width,
position[1] + height,
)
// Take the thumbnail of the task without a scrim and apply it back after
val alpha = mThumbnailView.dimAlpha
mThumbnailView.dimAlpha = 0f
val thumbnail = RecentsTransition.drawViewIntoHardwareBitmap(
taskBounds.width(),
taskBounds.height(),
mThumbnailView,
1f,
Color.BLACK,
)
mThumbnailView.dimAlpha = alpha
val future: AppTransitionAnimationSpecsFuture = object : AppTransitionAnimationSpecsFuture(mHandler) {
override fun composeSpecs(): List<AppTransitionAnimationSpecCompat> {
return listOf(
AppTransitionAnimationSpecCompat(
taskId,
thumbnail,
taskBounds,
),
)
}
}
try {
WindowManagerGlobal.getWindowManagerService()
.overridePendingAppTransitionMultiThumbFuture(
future.future,
RecentsTransition.wrapStartedListener(
mHandler,
animStartedListener,
),
true,
taskKey.displayId,
)
} catch (e: RemoteException) {
Log.w("TAG", "Failed to override pending app transition (multi-thumbnail future): ", e)
}
mTarget.statsLogManager.logger().withItemInfo(mTaskView.itemInfo).log(mLauncherEvent)
}
}
}
@JvmField
var legacySplit: TaskShortcutFactory = object : TaskShortcutFactory {
override fun getShortcuts(
activity: BaseDraggingActivity,
taskContainer: TaskIdAttributeContainer,
): List<SystemShortcut<*>>? {
val task = taskContainer.task
if (!task.isDockable) {
return null
}
return if (isAvailable(activity, task.key.displayId)) {
listOf(
LegacySplitSystemShortcut(
R.drawable.ic_split_vertical,
R.string.recent_task_option_split_screen,
activity,
taskContainer,
LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP,
),
)
} else {
null
}
}
private fun isAvailable(activity: BaseDraggingActivity, displayId: Int): Boolean {
return if (LawnchairQuickstepCompat.ATLEAST_T) {
false
} else {
(
!activity.deviceProfile.isMultiWindowMode &&
(displayId == -1 || displayId == Display.DEFAULT_DISPLAY)
)
}
}
}
}
@@ -9,6 +9,7 @@ import android.content.Context
import android.os.Bundle
import android.os.Handler
import androidx.core.os.bundleOf
import app.lawnchair.compat.LawnchairQuickstepCompat
import app.lawnchair.preferences.PreferenceChangeListener
import app.lawnchair.preferences.PreferenceManager
import app.lawnchair.util.requireSystemService
@@ -66,6 +67,7 @@ class LawnchairDeviceSearchAlgorithm(context: Context) :
}
private fun createSearchSession() {
if (LawnchairQuickstepCompat.ATLEAST_U) return
Executors.UI_HELPER_EXECUTOR.execute {
searchSession?.destroy()
val idp = LauncherAppState.getIDP(context)
@@ -122,6 +124,7 @@ class LawnchairDeviceSearchAlgorithm(context: Context) :
companion object {
fun checkSearchCompatibility(context: Context) {
if (LawnchairQuickstepCompat.ATLEAST_U) return
Executors.UI_HELPER_EXECUTOR.execute {
val searchContext = SearchContext(1 or 2, 200, Bundle())
val searchManager = context.requireSystemService<SearchUiManager>()
@@ -8,12 +8,13 @@ import android.view.WindowManager
import androidx.annotation.Keep
import app.lawnchair.LawnchairApp
import com.android.internal.policy.SystemBarUtils
import com.android.launcher3.Utilities
import com.android.launcher3.util.WindowBounds
import com.android.launcher3.util.window.CachedDisplayInfo
import com.android.launcher3.util.window.WindowManagerProxy
@Keep
class LawnchairWindowManagerProxy(context: Context) : WindowManagerProxy(true) {
class LawnchairWindowManagerProxy(context: Context) : WindowManagerProxy(Utilities.ATLEAST_T) {
override fun getRotation(displayInfoContext: Context): Int {
if (LawnchairApp.isAtleastT) {
@@ -0,0 +1,202 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.wm.shell.util;
import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
/**
* Simple container for recent tasks. May contain either a single or pair of tasks.
*/
public class GroupedRecentTaskInfo implements Parcelable {
public static final int TYPE_SINGLE = 1;
public static final int TYPE_SPLIT = 2;
public static final int TYPE_FREEFORM = 3;
@IntDef(prefix = {"TYPE_"}, value = {
TYPE_SINGLE ,
TYPE_SPLIT ,
TYPE_FREEFORM
})
public @interface GroupType {
}
@NonNull
private final ActivityManager.RecentTaskInfo[] mTasks;
@Nullable
private final SplitBounds mSplitBounds;
@GroupType
private final int mType;
/**
* Create new for a single task
*/
public static GroupedRecentTaskInfo forSingleTask(
@NonNull ActivityManager.RecentTaskInfo task) {
return new GroupedRecentTaskInfo (new ActivityManager.RecentTaskInfo[]{task} , null ,
TYPE_SINGLE);
}
/**
* Create new for a pair of tasks in split screen
*/
public static GroupedRecentTaskInfo forSplitTasks(@NonNull ActivityManager.RecentTaskInfo task1 ,
@NonNull ActivityManager.RecentTaskInfo task2 , @Nullable SplitBounds splitBounds) {
return new GroupedRecentTaskInfo (new ActivityManager.RecentTaskInfo[]{task1 , task2} ,
splitBounds , TYPE_SPLIT);
}
/**
* Create new for a group of freeform tasks
*/
public static GroupedRecentTaskInfo forFreeformTasks(
@NonNull ActivityManager.RecentTaskInfo... tasks) {
return new GroupedRecentTaskInfo (tasks , null , TYPE_FREEFORM);
}
private GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo[] tasks ,
@Nullable SplitBounds splitBounds , @GroupType int type) {
mTasks = tasks;
mSplitBounds = splitBounds;
mType = type;
}
GroupedRecentTaskInfo(Parcel parcel) {
mTasks = parcel.createTypedArray(ActivityManager.RecentTaskInfo.CREATOR);
mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR);
mType = parcel.readInt();
}
/**
* Get primary {@link ActivityManager.RecentTaskInfo}
*/
@NonNull
public ActivityManager.RecentTaskInfo getTaskInfo1() {
return mTasks[0];
}
/**
* Get secondary {@link ActivityManager.RecentTaskInfo}.
* <p>
* Used in split screen.
*/
@Nullable
public ActivityManager.RecentTaskInfo getTaskInfo2() {
if (mTasks.length > 1) {
return mTasks[1];
}
return null;
}
/**
* Get all {@link ActivityManager.RecentTaskInfo}s grouped together.
*/
@NonNull
public List<ActivityManager.RecentTaskInfo> getTaskInfoList() {
return Arrays.asList (mTasks);
}
/**
* Return {@link SplitBounds} if this is a split screen entry or {@code null}
*/
@Nullable
public SplitBounds getSplitBounds() {
return mSplitBounds;
}
/**
* Get type of this recents entry. One of {@link GroupType}
*/
@GroupType
public int getType() {
return mType;
}
@Override
public String toString() {
StringBuilder taskString = new StringBuilder ( );
for (int i = 0; i < mTasks.length; i++) {
if (i == 0) {
taskString.append ("Task");
} else {
taskString.append (", Task");
}
taskString.append (i + 1).append (": ").append (getTaskInfo (mTasks[i]));
}
if (mSplitBounds != null) {
taskString.append (", SplitBounds: ").append (mSplitBounds);
}
taskString.append (", Type=");
switch (mType) {
case TYPE_SINGLE:
taskString.append ("TYPE_SINGLE");
break;
case TYPE_SPLIT:
taskString.append ("TYPE_SPLIT");
break;
case TYPE_FREEFORM:
taskString.append ("TYPE_FREEFORM");
break;
}
return taskString.toString();
}
private String getTaskInfo(ActivityManager.RecentTaskInfo taskInfo) {
if (taskInfo == null) {
return null;
}
return "id=" + taskInfo.taskId
+ " baseIntent=" + (taskInfo.baseIntent != null
? taskInfo.baseIntent.getComponent ( )
: "null")
+ " winMode=" + WindowConfiguration.windowingModeToString (
taskInfo.getWindowingMode());
}
@Override
public void writeToParcel(Parcel parcel , int flags) {
parcel.writeTypedArray(mTasks , flags);
parcel.writeTypedObject(mSplitBounds , flags);
parcel.writeInt(mType);
}
@Override
public int describeContents() {
return 0;
}
public static final @android.annotation.NonNull Creator<GroupedRecentTaskInfo> CREATOR =
new Creator<GroupedRecentTaskInfo> ( ) {
public GroupedRecentTaskInfo createFromParcel(Parcel source) {
return new GroupedRecentTaskInfo(source);
}
public GroupedRecentTaskInfo[] newArray(int size) {
return new GroupedRecentTaskInfo[size];
}
};
}
Binary file not shown.
Binary file not shown.
@@ -127,6 +127,10 @@ public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat {
});
}
public void onAnimationCancelled(boolean isKeyguardOccluded) {
onAnimationCancelled();
}
/**
* Used by RemoteAnimationFactory implementations to run the actual animation and its lifecycle
* callbacks.
@@ -196,13 +200,19 @@ public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat {
finish();
}
});
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
mAnimator.start();
}
if (skipFirstFrame) {
// Because t=0 has the app icon in its original spot, we can skip the
// first frame and have the same movement one frame earlier.
mAnimator.setCurrentPlayTime(
Math.min(getSingleFrameMs(context), mAnimator.getTotalDuration()));
}
mAnimator.start();
if (Utilities.ATLEAST_U) {
mAnimator.start();
}
}
}
@@ -234,6 +244,11 @@ public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat {
RemoteAnimationTarget[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result);
@UiThread
default void onAnimationCancelled(boolean isKeyguardOccluded) {
onAnimationCancelled();
}
/**
* Called when the animation is cancelled. This can happen with or without
* the create being called.
@@ -164,6 +164,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import app.lawnchair.LawnchairApp;
import app.lawnchair.compat.LawnchairQuickstepCompat;
import app.lawnchair.icons.shape.IconShapeManager;
import app.lawnchair.theme.color.ColorTokens;
@@ -282,9 +283,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
}
};
mStartingWindowListener.setTransitionManager(this);
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(
mStartingWindowListener);
if (Utilities.ATLEAST_T) {
mStartingWindowListener.setTransitionManager(this);
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(
mStartingWindowListener);
}
}
mOpeningXInterpolator = AnimationUtils.loadInterpolator(context, R.interpolator.app_open_x);
@@ -333,10 +336,12 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY;
ActivityOptions options = ActivityOptions.makeRemoteAnimation(
ActivityOptions options = LawnchairQuickstepCompat.getActivityOptionsCompat().makeRemoteAnimation(
new RemoteAnimationAdapter(runner, duration, statusBarTransitionDelay),
new RemoteTransition(runner.toRemoteTransition(),
mLauncher.getIApplicationThread(), "QuickstepLaunch"));
LawnchairQuickstepCompat.getRemoteTransitionCompat().getRemoteTransition(runner.toRemoteTransition(),
mLauncher.getIApplicationThread(), "QuickstepLaunch"),
"Lawnchair");
return new ActivityOptionsWrapper(options, onEndCallback);
}
@@ -457,7 +462,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
if (target == null)
return new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
final Rect bounds = new Rect(target.screenSpaceBounds);
if (target.localBounds != null) {
if (Utilities.ATLEAST_R && target.localBounds != null) {
bounds.set(target.localBounds);
} else {
bounds.offsetTo(target.position.x, target.position.y);
@@ -864,7 +869,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
} else {
tmpPos.set(target.position.x, target.position.y);
}
final Rect crop = new Rect(target.screenSpaceBounds);
final Rect crop = new Rect(Utilities.ATLEAST_R ? target.screenSpaceBounds : target.sourceContainerBounds);
crop.offsetTo(0, 0);
if ((rotationChange % 2) == 1) {
@@ -1107,9 +1112,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
* Registers remote animations used when closing apps to home screen.
*/
public void registerRemoteAnimations() {
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
if (SEPARATE_RECENTS_ACTIVITY.get() || !Utilities.ATLEAST_S) return;
if (hasControlRemoteAppTransitionPermission()) {
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
addRemoteAnimations(definition);
@@ -1147,17 +1150,16 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
* Registers remote animations used when closing apps to home screen.
*/
public void registerRemoteTransitions() {
if (ENABLE_SHELL_TRANSITIONS && Utilities.ATLEAST_U) {
if (ENABLE_SHELL_TRANSITIONS && LawnchairQuickstepCompat.ATLEAST_U) {
SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
}
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
if (!Utilities.ATLEAST_S)
return;
if (!LawnchairQuickstepCompat.ATLEAST_T) return;
if (hasControlRemoteAppTransitionPermission()) {
mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */);
mLauncherOpenTransition = new RemoteTransition(
mLauncherOpenTransition = LawnchairQuickstepCompat.getRemoteTransitionCompat().getRemoteTransition(
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
false /* startAtFrontOfQueue */).toRemoteTransition(),
mLauncher.getIApplicationThread(), "QuickstepLaunchHome");
@@ -1184,8 +1186,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
public void onActivityDestroyed() {
unregisterRemoteAnimations();
unregisterRemoteTransitions();
mStartingWindowListener.setTransitionManager(null);
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
if (Utilities.ATLEAST_T) {
mStartingWindowListener.setTransitionManager(null);
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
}
}
private void unregisterRemoteAnimations() {
@@ -1193,8 +1197,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
return;
}
if (hasControlRemoteAppTransitionPermission()) {
mLauncher.unregisterRemoteAnimations();
if (Utilities.ATLEAST_R) {
mLauncher.unregisterRemoteAnimations();
}
// Also clear strong references to the runners registered with the remote
// animation
// definition so we don't have to wait for the system gc
@@ -1212,8 +1217,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
return;
}
if (hasControlRemoteAppTransitionPermission()) {
if (mLauncherOpenTransition == null)
return;
if (mLauncherOpenTransition == null) return;
SystemUiProxy.INSTANCE.get(mLauncher).unregisterRemoteTransition(
mLauncherOpenTransition);
mLauncherOpenTransition = null;
@@ -1227,6 +1231,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
private boolean launcherIsATargetWithMode(RemoteAnimationTarget[] targets, int mode) {
for (RemoteAnimationTarget target : targets) {
if (!Utilities.ATLEAST_S) {
return target.mode == mode && target.taskId == mLauncher.getTaskId();
}
if (target.mode == mode && target.taskInfo != null
// Compare component name instead of task-id because transitions will promote
// the target up to the root task while getTaskId returns the leaf.
@@ -1277,7 +1284,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
RemoteAnimationTarget target = appTargets[i];
transaction.forSurface(target.leash)
.setAlpha(1f)
.setWindowCrop(target.screenSpaceBounds)
.setWindowCrop(Utilities.ATLEAST_R ? target.screenSpaceBounds : target.sourceContainerBounds)
.setCornerRadius(cornerRadius);
}
surfaceApplier.scheduleApply(transaction);
@@ -1304,6 +1311,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
* app targets
*/
private @Nullable View findLauncherView(RemoteAnimationTarget[] appTargets) {
if (!Utilities.ATLEAST_S) return null;
for (RemoteAnimationTarget appTarget : appTargets) {
if (appTarget.mode == MODE_CLOSING) {
View launcherView = findLauncherView(appTarget);
@@ -2018,7 +2026,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
RemoteAnimationTarget target = mAppTargets[i];
SurfaceProperties builder = transaction.forSurface(target.leash);
if (target.localBounds != null) {
if (Utilities.ATLEAST_R && target.localBounds != null) {
mTmpPos.set(target.localBounds.left, target.localBounds.top);
} else {
mTmpPos.set(target.position.x, target.position.y);
@@ -86,6 +86,7 @@ import java.util.Objects;
import java.util.stream.IntStream;
import app.lawnchair.LawnchairApp;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Model delegate which loads prediction items
@@ -259,8 +260,9 @@ public class QuickstepModelDelegate extends ModelDelegate {
* atom.
*/
protected void registerSnapshotLoggingCallback() {
if (mStatsManager == null) {
if (mStatsManager == null || !LawnchairQuickstepCompat.ATLEAST_R) {
Log.d(TAG, "Failed to get StatsManager");
return;
}
try {
@@ -330,7 +332,7 @@ public class QuickstepModelDelegate extends ModelDelegate {
super.destroy();
mActive = false;
StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
if (mIsPrimaryInstance) {
if (mIsPrimaryInstance && LawnchairQuickstepCompat.ATLEAST_R) {
mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
}
destroyPredictors();
@@ -41,6 +41,8 @@ import com.android.quickstep.util.BaseDepthController;
import java.io.PrintWriter;
import java.util.function.Consumer;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Controls blur and wallpaper zoom, for the Launcher surface only.
*/
@@ -77,7 +79,7 @@ public class DepthController extends BaseDepthController implements StateHandler
mOnAttachListener = new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
if (app.lawnchair.LawnchairApp.isAtleastT()) {
if (LawnchairQuickstepCompat.ATLEAST_S) {
CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
mCrossWindowBlurListener);
}
@@ -114,7 +116,7 @@ public class DepthController extends BaseDepthController implements StateHandler
}
private void removeSecondaryListeners() {
if (mCrossWindowBlurListener != null) {
if (mCrossWindowBlurListener != null && LawnchairQuickstepCompat.ATLEAST_S) {
CrossWindowBlurListeners.getInstance().removeListener(mCrossWindowBlurListener);
}
if (mOpaquenessListener != null) {
@@ -239,9 +239,11 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
WindowManagerGlobal.getWindowManagerService().clearTaskTransitionSpec();
} else {
// Adjust task transition spec to account for taskbar being visible
WindowManagerGlobal.getWindowManagerService().setTaskTransitionSpec(
new TaskTransitionSpec(
mLauncher.getColor(R.color.taskbar_background)));
if (Utilities.ATLEAST_U) {
WindowManagerGlobal.getWindowManagerService().setTaskTransitionSpec(
new TaskTransitionSpec(
mLauncher.getColor(R.color.taskbar_background)));
}
}
} catch (RemoteException e) {
// This shouldn't happen but if it does task animations won't look good until the
@@ -645,7 +645,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
this, 0, 0, Color.TRANSPARENT,
Executors.MAIN_EXECUTOR.getHandler(), null,
elapsedRealTime -> callbacks.executeAllAndDestroy());
options.setSplashScreenStyle(splashScreenStyle);
if (Utilities.ATLEAST_T) {
options.setSplashScreenStyle(splashScreenStyle);
}
Utilities.allowBGLaunch(options);
return new ActivityOptionsWrapper(options, callbacks);
}
@@ -34,6 +34,7 @@ import androidx.annotation.Nullable;
import com.android.app.viewcapture.SettingsAwareViewCapture;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Utilities;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.MultiPropertyFactory;
@@ -131,14 +132,18 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnComputeInternalInsetsListener(mTaskbarInsetsComputer);
mViewCaptureCloseable = SettingsAwareViewCapture.getInstance(getContext())
.startCapture(getRootView(), ".Taskbar");
if (Utilities.ATLEAST_U) {
mViewCaptureCloseable = SettingsAwareViewCapture.getInstance(getContext())
.startCapture(getRootView(), ".Taskbar");
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mViewCaptureCloseable.close();
if (Utilities.ATLEAST_U) {
mViewCaptureCloseable.close();
}
onDestroy(true);
}
@@ -77,7 +77,11 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
gestureNavSettingsObserver.registerForCallingUser()
try {
gestureNavSettingsObserver.registerForCallingUser()
} catch (t: Throwable) {
// Ignore
}
}
fun onDestroy() {
@@ -161,19 +165,23 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
private fun getProvidedInsets(insetsRoundedCornerFlag: Int): Array<InsetsFrameProvider> {
val navBarsFlag =
(if (context.isGestureNav) FLAG_SUPPRESS_SCRIM else 0) or insetsRoundedCornerFlag
return arrayOf(
try {
return arrayOf(
InsetsFrameProvider(insetsOwner, 0, navigationBars())
.setFlags(
navBarsFlag,
FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER
),
.setFlags(
navBarsFlag,
FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER
),
InsetsFrameProvider(insetsOwner, 0, tappableElement()),
InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures()),
InsetsFrameProvider(insetsOwner, INDEX_LEFT, systemGestures())
.setSource(SOURCE_DISPLAY),
.setSource(SOURCE_DISPLAY),
InsetsFrameProvider(insetsOwner, INDEX_RIGHT, systemGestures())
.setSource(SOURCE_DISPLAY)
)
.setSource(SOURCE_DISPLAY)
)
}catch (t: Throwable) {
return emptyArray()
}
}
private fun setProviderInsets(provider: InsetsFrameProvider, gravity: Int) {
@@ -18,6 +18,7 @@ package com.android.launcher3.taskbar;
import static android.content.Context.RECEIVER_NOT_EXPORTED;
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
@@ -54,6 +55,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
@@ -72,6 +74,8 @@ import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
import java.io.PrintWriter;
import java.util.StringJoiner;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Class to manage taskbar lifecycle
*/
@@ -207,8 +211,16 @@ public class TaskbarManager {
@SuppressLint("WrongConstant")
public TaskbarManager(TouchInteractionService service) {
Display display = service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = (LawnchairQuickstepCompat.ATLEAST_T) ?
service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null) :
(LawnchairQuickstepCompat.ATLEAST_S) ?
service.createWindowContext(display, TYPE_APPLICATION_OVERLAY, null) :
(LawnchairQuickstepCompat.ATLEAST_R) ?
service.createWindowContext(TYPE_APPLICATION_OVERLAY, null) :
service;
mNavButtonController = new TaskbarNavButtonController(service,
SystemUiProxy.INSTANCE.get(mContext), new Handler(),
AssistUtils.newInstance(mContext));
@@ -217,8 +229,10 @@ public class TaskbarManager {
@Override
public void onConfigurationChanged(Configuration newConfig) {
Trace.instantForTrack(Trace.TRACE_TAG_APP, "TaskbarManager",
"onConfigurationChanged: " + newConfig);
if (LawnchairQuickstepCompat.ATLEAST_T) {
Trace.instantForTrack(Trace.TRACE_TAG_APP, "TaskbarManager",
"onConfigurationChanged: " + newConfig);
}
debugWhyTaskbarNotDestroyed(
"TaskbarManager#mComponentCallbacks.onConfigurationChanged: " + newConfig);
DeviceProfile dp = mUserUnlocked
@@ -96,7 +96,9 @@ public class QuickstepInteractionHandler implements RemoteViews.InteractionHandl
// Do nothing.
}
activityOptions.options.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
if (Utilities.ATLEAST_T) {
activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
}
Utilities.allowBGLaunch(activityOptions.options);
}
@@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
@@ -67,11 +66,9 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
import android.media.permission.SafeCloseable;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemProperties;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
@@ -86,7 +83,7 @@ import android.window.SplashScreen;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.app.viewcapture.SettingsAwareViewCapture;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
@@ -186,6 +183,8 @@ import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import app.lawnchair.compat.LawnchairQuickstepCompat;
public class QuickstepLauncher extends Launcher {
private static final boolean TRACE_LAYOUTS = SystemProperties.getBoolean("persist.debug.trace_layouts", false);
private static final String TRACE_RELAYOUT_CLASS = SystemProperties.get("persist.debug.trace_request_layout_class",
@@ -1020,24 +1019,24 @@ public class QuickstepLauncher extends Launcher {
ActivityOptionsWrapper activityOptions = mAppTransitionManager.hasControlRemoteAppTransitionPermission()
? mAppTransitionManager.getActivityLaunchOptions(v)
: super.getActivityLaunchOptions(v, item);
if (mLastTouchUpTime > 0 && app.lawnchair.LawnchairApp.isAtleastT()) {
if (mLastTouchUpTime > 0 && LawnchairQuickstepCompat.ATLEAST_S) {
activityOptions.options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER,
mLastTouchUpTime);
}
if (item != null && (item.animationType == DEFAULT_NO_ICON
|| item.animationType == VIEW_BACKGROUND) && app.lawnchair.LawnchairApp.isAtleastT()) {
|| item.animationType == VIEW_BACKGROUND) && LawnchairQuickstepCompat.ATLEAST_T) {
activityOptions.options.setSplashScreenStyle(
SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
} else {
if (app.lawnchair.LawnchairApp.isAtleastT()) {
if (LawnchairQuickstepCompat.ATLEAST_T) {
activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
}
}
activityOptions.options.setLaunchDisplayId(
(v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
: Display.DEFAULT_DISPLAY);
if (app.lawnchair.LawnchairApp.isAtleastT()) {
Utilities.allowBGLaunch(activityOptions.options);
Utilities.allowBGLaunch(activityOptions.options);
if (LawnchairQuickstepCompat.ATLEAST_T) {
addLaunchCookie(item, activityOptions.options);
}
return activityOptions;
@@ -1046,11 +1045,13 @@ public class QuickstepLauncher extends Launcher {
@Override
public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
RunnableList callbacks = new RunnableList();
ActivityOptions options = ActivityOptions.makeCustomAnimation(
ActivityOptions options = LawnchairQuickstepCompat.ATLEAST_R ? ActivityOptions.makeCustomAnimation(
this, 0, 0, Color.TRANSPARENT,
Executors.MAIN_EXECUTOR.getHandler(), null,
elapsedRealTime -> callbacks.executeAllAndDestroy());
options.setSplashScreenStyle(splashScreenStyle);
elapsedRealTime -> callbacks.executeAllAndDestroy()) : ActivityOptions.makeBasic();
if (LawnchairQuickstepCompat.ATLEAST_T) {
options.setSplashScreenStyle(splashScreenStyle);
}
Utilities.allowBGLaunch(options);
return new ActivityOptionsWrapper(options, callbacks);
}
@@ -101,15 +101,12 @@ import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarThresholdUtils;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.tracing.InputConsumerProto;
import com.android.launcher3.tracing.SwipeHandlerProto;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
import com.android.launcher3.util.DisplayController;
@@ -157,6 +154,7 @@ import java.util.Optional;
import java.util.OptionalInt;
import java.util.function.Consumer;
import app.lawnchair.compat.LawnchairQuickstepCompat;
import app.lawnchair.util.CompatibilityKt;
/**
@@ -672,15 +670,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, Q extends
runningTasks = cachedTaskInfo.getPlaceholderTasks();
}
// Safeguard against any null tasks being sent to recents view, happens when
// quickswitching
// very quickly w/ split tasks because TopTaskTracker provides stale information
// compared to
// actual running tasks in the recents animation.
// TODO(b/236226779), Proper fix (ag/22237143)
if (Arrays.stream(runningTasks).anyMatch(Objects::isNull)) {
return;
}
// Safeguard against any null tasks being sent to recents view, happens when
// quickswitching
@@ -702,8 +691,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, Q extends
buildAnimationController();
try (SafeCloseable c = TraceHelper.INSTANCE.allowIpcs("logToggleRecents")) {
LatencyTracker.getInstance(mContext).logAction(LatencyTracker.ACTION_TOGGLE_RECENTS,
(int) (mLauncherFrameDrawnTime - mTouchTimeMs));
if (Utilities.ATLEAST_S) {
LatencyTracker.getInstance(mContext).logAction(LatencyTracker.ACTION_TOGGLE_RECENTS,
(int) (mLauncherFrameDrawnTime - mTouchTimeMs));
}
}
// This method is only called when STATE_GESTURE_STARTED is set, so we can
@@ -713,8 +704,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, Q extends
RecentsModel.INSTANCE.get(mContext).getThumbnailCache()
.getHighResLoadingState().setVisible(true);
DepthController depthController = mActivityInterface.getDepthController();
}
public MotionPauseDetector.OnMotionPauseListener getMotionPauseListener() {
@@ -1561,7 +1550,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, Q extends
? mRecentsAnimationTargets
.findTask(mGestureState.getTopRunningTaskId())
: null;
final ArrayList<IBinder> cookies = runningTaskTarget != null
final ArrayList<IBinder> cookies = Utilities.ATLEAST_S && runningTaskTarget != null
&& runningTaskTarget.taskInfo != null
? runningTaskTarget.taskInfo.launchCookies
: new ArrayList<>();
@@ -1571,6 +1560,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, Q extends
&& runningTaskTarget.leash.isValid();
boolean appCanEnterPip = !mDeviceState.isPipActive()
&& hasValidLeash
&& Utilities.ATLEAST_T
&& runningTaskTarget.allowEnterPip
&& runningTaskTarget.taskInfo.pictureInPictureParams != null
&& runningTaskTarget.taskInfo.pictureInPictureParams.isAutoEnterEnabled();
@@ -2221,14 +2211,22 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, Q extends
} else if (mIsSwipeForSplit) {
// Transaction to hide the task to avoid flicker for entering PiP from
// split-screen.
PictureInPictureSurfaceTransaction tx = new PictureInPictureSurfaceTransaction.Builder()
.setAlpha(0f)
.build();
tx.setShouldDisableCanAffectSystemUiFlags(false);
int[] taskIds = TopTaskTracker.INSTANCE.get(mContext).getRunningSplitTaskIds();
for (int taskId : taskIds) {
mRecentsAnimationController.setFinishTaskTransaction(taskId,
tx, null /* overlay */);
try {
PictureInPictureSurfaceTransaction tx = new PictureInPictureSurfaceTransaction.Builder()
.setAlpha(0f)
.build();
try {
tx.setShouldDisableCanAffectSystemUiFlags(false);
} catch (NoSuchMethodError error) {
Log.w(TAG, "not android 13 qpr1 : ", error);
}
int[] taskIds = TopTaskTracker.INSTANCE.get(mContext).getRunningSplitTaskIds();
for (int taskId : taskIds) {
mRecentsAnimationController.setFinishTaskTransaction(taskId,
tx, null /* overlay */);
}
} catch (Throwable t) {
Log.w(TAG, "Failed PictureInPictureSurfaceTransaction: ", t);
}
}
}
@@ -2437,7 +2435,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, Q extends
transaction.forSurface(target.leash).setAlpha(1).setLayer(-1).setShow();
}
surfaceApplier.scheduleApply(transaction);
if (!LawnchairQuickstepCompat.ATLEAST_S) return;
SplashScreenExitAnimationUtils.startAnimations(splashView, taskTarget.leash,
mSplashMainWindowShiftLength, new TransactionPool(), new Rect(),
SPLASH_ANIMATION_DURATION, SPLASH_FADE_OUT_DURATION,
@@ -30,6 +30,7 @@ import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSaf
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.content.Context;
@@ -71,6 +72,7 @@ import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import java.lang.ref.WeakReference;
@@ -78,6 +80,8 @@ import java.util.ArrayList;
import java.util.UUID;
import java.util.function.Consumer;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
*/
@@ -160,8 +164,9 @@ public class FallbackSwipeHandler extends
@Nullable RemoteAnimationTarget runningTaskTarget) {
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
Intent intent = new Intent(mGestureState.getHomeIntent());
if (gestureContractAnimationFactory != null && runningTaskTarget != null) {
gestureContractAnimationFactory.addGestureContract(intent, runningTaskTarget.taskInfo);
var runningTask = TopTaskTracker.INSTANCE.get(mContext).getCachedTopTask(true);
if (gestureContractAnimationFactory != null && runningTaskTarget != null && runningTask.getTaskId() == runningTaskTarget.taskId) {
gestureContractAnimationFactory.addGestureContract(intent, runningTask.mAllCachedTasks.get(0));
}
startHomeIntentSafely(mContext, intent, options.toBundle());
}
@@ -214,7 +214,10 @@ public class LauncherBackAnimationController {
mAnimationFinishedCallback = finishedCallback;
}
@Override
void onAnimationCancelled(boolean isKeyguardOccluded) {
onAnimationCancelled();
}
public void onAnimationCancelled() {
}
};
@@ -23,6 +23,8 @@ import android.graphics.RectF;
import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.Utilities;
public class OrientationRectF extends RectF {
private static final String TAG = "OrientationRectF";
@@ -76,7 +78,11 @@ public class OrientationRectF extends RectF {
+ "mRotation: " + mRotation
+ " this: " + this);
}
event.applyTransform(mTmpMatrix);
if (Utilities.ATLEAST_S) {
event.applyTransform(mTmpMatrix);
} else {
event.transform(mTmpMatrix);
}
return true;
}
mTmpPoint[0] = event.getX();
@@ -92,7 +98,11 @@ public class OrientationRectF extends RectF {
}
if (contains(mTmpPoint[0], mTmpPoint[1])) {
event.applyTransform(mTmpMatrix);
if (Utilities.ATLEAST_S) {
event.applyTransform(mTmpMatrix);
} else {
event.transform(mTmpMatrix);
}
return true;
}
return false;
@@ -34,11 +34,14 @@ import android.util.SparseBooleanArray;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.SplitBounds;
@@ -51,6 +54,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import app.lawnchair.LawnchairApp;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Manages the recent task list from the system, caching it as necessary.
@@ -83,26 +87,60 @@ public class RecentTasksList {
mKeyguardManager = keyguardManager;
mChangeId = 1;
mSysUiProxy = sysUiProxy;
sysUiProxy.registerRecentTasksListener(new IRecentTasksListener.Stub() {
@Override
public void onRecentTasksChanged() throws RemoteException {
mMainThreadExecutor.execute(RecentTasksList.this::onRecentTasksChanged);
}
@Override
public void onRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
mMainThreadExecutor.execute(() -> {
RecentTasksList.this.onRunningTaskAppeared(taskInfo);
if (LawnchairApp.isRecentsEnabled()) {
if (LawnchairQuickstepCompat.ATLEAST_U) {
sysUiProxy.registerRecentTasksListener(new IRecentTasksListener.Stub() {
@Override
public void onRecentTasksChanged() throws RemoteException {
mMainThreadExecutor.execute(RecentTasksList.this::onRecentTasksChanged);
}
@Override
public void onRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
mMainThreadExecutor.execute(() -> {
RecentTasksList.this.onRunningTaskAppeared(taskInfo);
});
}
@Override
public void onRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
mMainThreadExecutor.execute(() -> {
RecentTasksList.this.onRunningTaskVanished(taskInfo);
});
}
});
} else if (LawnchairQuickstepCompat.ATLEAST_Q) {
TaskStackChangeListeners.getInstance().registerTaskStackListener(new TaskStackChangeListener () {
@Override
public void onTaskStackChanged() {
onRecentTasksChanged();
}
@Override
public void onRecentTaskListUpdated() {
onRecentTasksChanged();
}
@Override
public void onTaskRemoved(int taskId) {
onRecentTasksChanged();
}
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
onRecentTasksChanged();
}
@Override
public void onActivityUnpinned() {
onRecentTasksChanged();
}
});
}
@Override
public void onRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
mMainThreadExecutor.execute(() -> {
RecentTasksList.this.onRunningTaskVanished(taskInfo);
});
}
});
}
// We may receive onRunningTaskAppeared events later for tasks which have already been
// included in the list returned by mSysUiProxy.getRunningTasks(), or may receive
// onRunningTaskVanished for tasks not included in the returned list. These cases will be
@@ -297,7 +335,7 @@ public class RecentTasksList {
: Task.from(task2Key, taskInfo2,
tmpLockedUsers.get(task2Key.userId) /* isLocked */);
task2.setLastSnapshotData(taskInfo2);
} else {
} else if (Utilities.ATLEAST_S) {
// Is fullscreen task
if (numVisibleTasks > 0) {
boolean isExcluded = (taskInfo1.baseIntent.getFlags()
@@ -309,8 +347,10 @@ public class RecentTasksList {
}
}
}
if (taskInfo1.isVisible) {
numVisibleTasks++;
if (Utilities.ATLEAST_S) {
if (taskInfo1.isVisible) {
numVisibleTasks++;
}
}
final SplitConfigurationOptions.SplitBounds launcherSplitBounds =
convertSplitBounds(rawTask.getSplitBounds());
@@ -15,7 +15,6 @@
*/
package com.android.quickstep;
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
@@ -36,7 +35,6 @@ import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Trace;
import android.util.Log;
import android.view.Display;
import android.view.RemoteAnimationAdapter;
@@ -91,6 +89,8 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* A recents activity that shows the recently launched tasks as swipable task
* cards.
@@ -275,15 +275,16 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
final LauncherAnimationRunner wrapper = new LauncherAnimationRunner(
mUiHandler, mActivityLaunchAnimationRunner, true /* startAtFrontOfQueue */);
final ActivityOptions options = ActivityOptions.makeRemoteAnimation(
final ActivityOptions options = LawnchairQuickstepCompat.getActivityOptionsCompat().makeRemoteAnimation(
new RemoteAnimationAdapter(wrapper, RECENTS_LAUNCH_DURATION,
RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY),
new RemoteTransition(wrapper.toRemoteTransition(), getIApplicationThread(),
"LaunchFromRecents"));
LawnchairQuickstepCompat.getRemoteTransitionCompat().getRemoteTransition(wrapper.toRemoteTransition(), getIApplicationThread(),
"LaunchFromRecents"),
"Lawnchair");
final ActivityOptionsWrapper activityOptions = new ActivityOptionsWrapper(options,
onEndCallback);
if (Utilities.ATLEAST_S) {
if (Utilities.ATLEAST_T) {
activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
activityOptions.options.setLaunchDisplayId(
(v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
@@ -422,10 +423,11 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
private void startHomeInternal() {
LauncherAnimationRunner runner = new LauncherAnimationRunner(
getMainThreadHandler(), mAnimationToHomeFactory, true);
ActivityOptions options = ActivityOptions.makeRemoteAnimation(
ActivityOptions options = LawnchairQuickstepCompat.getActivityOptionsCompat().makeRemoteAnimation(
new RemoteAnimationAdapter(runner, HOME_APPEAR_DURATION, 0),
new RemoteTransition(runner.toRemoteTransition(), getIApplicationThread(),
"StartHomeFromRecents"));
LawnchairQuickstepCompat.getRemoteTransitionCompat().getRemoteTransition(runner.toRemoteTransition(), getIApplicationThread(),
"StartHomeFromRecents"),
"Lawnchair");
startHomeIntentSafely(this, options.toBundle());
}
@@ -42,6 +42,8 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which
* delegates callbacks to multiple listeners on the main thread
@@ -125,7 +127,7 @@ public class RecentsAnimationCallbacks implements
} else {
RemoteAnimationTarget[] nonAppTargets;
if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
nonAppTargets = mSystemUiProxy.onGoingToRecentsLegacy(appTargets);
nonAppTargets = LawnchairQuickstepCompat.ATLEAST_T ? mSystemUiProxy.onGoingToRecentsLegacy(appTargets) : null;
} else {
final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
final ArrayList<RemoteAnimationTarget> nonApps = new ArrayList<>();
@@ -130,6 +130,7 @@ public class RemoteAnimationTargets {
}
private static void release(RemoteAnimationTarget[] targets) {
if (targets == null) return;
for (RemoteAnimationTarget target : targets) {
if (target.leash != null) {
target.leash.release();
@@ -29,8 +29,9 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
@@ -59,12 +60,15 @@ import androidx.annotation.WorkerThread;
import com.android.internal.logging.InstanceId;
import com.android.internal.util.ScreenshotRequest;
import com.android.internal.view.AppearanceRegion;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.util.AssistUtils;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RecentsAnimationListener;
import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController;
@@ -94,6 +98,10 @@ import com.android.wm.shell.util.GroupedRecentTaskInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Holds the reference to SystemUI.
@@ -231,7 +239,7 @@ public class SystemUiProxy implements ISystemUiProxy {
unlinkToDeath();
mSystemUiProxy = proxy;
mPip = pip;
mBubbles = bubbles;
mBubbles = Utilities.ATLEAST_U ? bubbles : null;
mSplitScreen = splitScreen;
mOneHanded = oneHanded;
mShellTransitions = shellTransitions;
@@ -241,7 +249,7 @@ public class SystemUiProxy implements ISystemUiProxy {
mBackAnimation = backAnimation;
mDesktopMode = desktopMode;
mUnfoldAnimation = unfoldAnimation;
mDragAndDrop = dragAndDrop;
mDragAndDrop = Utilities.ATLEAST_U ? dragAndDrop : null;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized
// yet.
@@ -360,6 +368,11 @@ public class SystemUiProxy implements ISystemUiProxy {
}
}
@Override
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
return null;
}
@Override
public void startAssistant(Bundle args) {
if (mSystemUiProxy != null) {
@@ -382,6 +395,18 @@ public class SystemUiProxy implements ISystemUiProxy {
}
}
@Override
public Bundle monitorGestureInput(String name, int displayId) {
if (mSystemUiProxy != null) {
try {
return mSystemUiProxy.monitorGestureInput(name, displayId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call monitorGestureInput: " + name, e);
}
}
return null;
}
@Override
public void notifyAccessibilityButtonClicked(int displayId) {
if (mSystemUiProxy != null) {
@@ -426,17 +451,6 @@ public class SystemUiProxy implements ISystemUiProxy {
}
}
// public void setTaskbarEnabled(boolean enabled) {
// if (mSystemUiProxy != null) {
// try {
// mSystemUiProxy.setTaskbarEnabled(enabled);
// } catch (RemoteException e) {
// Log.w(TAG, "Failed call setTaskbarEnabled with arg: " +
// enabled, e);
// }
// }
// }
public void notifyTaskbarStatus(boolean visible, boolean stashed) {
if (mSystemUiProxy != null) {
try {
@@ -477,6 +491,54 @@ public class SystemUiProxy implements ISystemUiProxy {
}
}
@Override
public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
Insets visibleInsets, Task.TaskKey task) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.handleImageBundleAsScreenshot(screenImageBundle, locationInScreen,
visibleInsets, task);
} catch (RemoteException e) {
Log.w(TAG, "Failed call handleImageBundleAsScreenshot");
}
}
}
public void handleImageAsScreenshot(Bitmap bitmap, Rect rect, Insets insets, int i) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.handleImageAsScreenshot(bitmap, rect, insets, i);
} catch (RemoteException e) {
Log.w(TAG, "Failed call handleImageAsScreenshot", e);
}
}
}
@Override
public void setSplitScreenMinimized(boolean minimized) throws RemoteException {}
@Override
public void notifySwipeToHomeFinished() {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.notifySwipeUpGestureStarted();
} catch (RemoteException e) {
Log.w(TAG, "Failed call notifySwipeUpGestureStarted", e);
}
}
}
@Override
public void notifySwipeUpGestureStarted() {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.notifySwipeToHomeFinished();
} catch (RemoteException e) {
Log.w(TAG, "Failed call notifySwipeToHomeFinished", e);
}
}
}
@Override
public void onStatusBarTrackpadEvent(MotionEvent event) {
if (mSystemUiProxy != null) {
@@ -527,7 +589,7 @@ public class SystemUiProxy implements ISystemUiProxy {
boolean visible = visibleInt != 0;
boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight;
IPip pip = mPip;
if (pip != null && changed) {
if (pip != null && changed && Utilities.ATLEAST_T) {
mLastShelfVisible = visible;
mLastShelfHeight = shelfHeight;
try {
@@ -544,8 +606,10 @@ public class SystemUiProxy implements ISystemUiProxy {
* the Launcher for the Hotseat.
*/
public void setLauncherKeepClearAreaHeight(boolean visible, int height) {
Message.obtain(mAsyncHandler, MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT,
visible ? 1 : 0, height).sendToTarget();
if (Utilities.ATLEAST_T) {
Message.obtain(mAsyncHandler, MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT,
visible ? 1 : 0, height).sendToTarget();
}
}
@WorkerThread
@@ -570,7 +634,7 @@ public class SystemUiProxy implements ISystemUiProxy {
* Sets listener to get pip animation callbacks.
*/
public void setPipAnimationListener(IPipAnimationListener listener) {
if (mPip != null) {
if (mPip != null && Utilities.ATLEAST_T) {
try {
mPip.setPipAnimationListener(listener);
} catch (RemoteException e) {
@@ -592,7 +656,7 @@ public class SystemUiProxy implements ISystemUiProxy {
try {
return mPip.startSwipePipToHome(componentName, activityInfo,
pictureInPictureParams, launcherRotation, hotseatKeepClearArea);
} catch (RemoteException e) {
} catch (Throwable e) {
Log.w(TAG, "Failed call startSwipePipToHome", e);
}
}
@@ -636,12 +700,16 @@ public class SystemUiProxy implements ISystemUiProxy {
* Sets the next pip animation type to be the alpha animation.
*/
public void setPipAnimationTypeToAlpha() {
if (mPip != null) {
try {
mPip.setPipAnimationTypeToAlpha();
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPipAnimationTypeToAlpha", e);
try {
if (mPip != null) {
try {
mPip.setPipAnimationTypeToAlpha();
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPipAnimationTypeToAlpha", e);
}
}
} catch (Throwable t) {
Log.w(TAG, "Failed call setPipAnimationTypeToAlpha not supported", t);
}
}
@@ -649,7 +717,7 @@ public class SystemUiProxy implements ISystemUiProxy {
* Sets the app icon size in pixel used by Launcher all apps.
*/
public void setLauncherAppIconSize(int iconSizePx) {
if (mPip != null) {
if (mPip != null && Utilities.ATLEAST_T) {
try {
mPip.setLauncherAppIconSize(iconSizePx);
} catch (RemoteException e) {
@@ -766,14 +834,18 @@ public class SystemUiProxy implements ISystemUiProxy {
//
public void registerSplitScreenListener(ISplitScreenListener listener) {
if (mSplitScreen != null) {
try {
mSplitScreen.registerSplitScreenListener(listener);
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerSplitScreenListener");
try {
if (mSplitScreen != null) {
try {
mSplitScreen.registerSplitScreenListener(listener);
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerSplitScreenListener");
}
}
mSplitScreenListener = listener;
} catch (Throwable t) {
Log.w (TAG , "Not supported: " , t);
}
mSplitScreenListener = listener;
}
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
@@ -871,7 +943,7 @@ public class SystemUiProxy implements ISystemUiProxy {
public void startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2,
Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
if (mSystemUiProxy != null) {
if (mSystemUiProxy != null && Utilities.ATLEAST_T) {
try {
mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2,
splitPosition, splitRatio, adapter, instanceId);
@@ -992,7 +1064,7 @@ public class SystemUiProxy implements ISystemUiProxy {
if (mSplitScreen != null) {
try {
return mSplitScreen.onStartingSplitLegacy(apps);
} catch (RemoteException e) {
} catch (Throwable e) {
Log.w(TAG, "Failed call onStartingSplitLegacy");
}
}
@@ -1243,27 +1315,34 @@ public class SystemUiProxy implements ISystemUiProxy {
}
public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
if (mRecentTasks != null) {
try {
if (!LawnchairQuickstepCompat.ATLEAST_U) {
return getRecentTasksFromWrapper(numTasks, userId);
}
try {
if (mRecentTasks != null) {
final GroupedRecentTaskInfo[] rawTasks = mRecentTasks.getRecentTasks(numTasks,
RECENT_IGNORE_UNAVAILABLE, userId);
if (rawTasks == null) {
return new ArrayList<>();
}
return new ArrayList<>(Arrays.asList(rawTasks));
} catch (RemoteException e) {
Log.w(TAG, "Failed call getRecentTasks", e);
}
} catch (Throwable t) {
Log.w(TAG, "Failed call getRecentTasks ,may be android 13- ", t);
return getRecentTasksFromWrapper(numTasks, userId);
}
return new ArrayList<>();
}
private ArrayList<GroupedRecentTaskInfo> getRecentTasksFromWrapper(int numTasks, int userId) {
List<ActivityManager.RecentTaskInfo> recentTaskInfoList = ActivityManagerWrapper.getInstance().getRecentTasks(numTasks, userId);
return recentTaskInfoList.stream()
.map(GroupedRecentTaskInfo::forSingleTask)
.collect(Collectors.toCollection(ArrayList::new));
}
/**
* Gets the set of running tasks.
*/
public ArrayList<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
if (mRecentTasks != null
&& mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) {
if (mRecentTasks != null) {
try {
return new ArrayList<>(Arrays.asList(mRecentTasks.getRunningTasks(numTasks)));
} catch (RemoteException e) {
@@ -32,6 +32,7 @@ import android.content.Intent;
import android.os.SystemProperties;
import android.util.Log;
import android.view.RemoteAnimationTarget;
import android.window.RemoteTransition;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -53,7 +54,7 @@ import java.util.HashMap;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
public static final boolean ENABLE_SHELL_TRANSITIONS = SystemProperties.getBoolean("persist.wm.debug.shell_transit",
true);
Utilities.ATLEAST_U);
public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
&& SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
@@ -274,10 +275,13 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
if (!homeIsOnTop) {
options.setTransientLaunch();
}
if (app.lawnchair.LawnchairApp.isAtleastT()) {
if (Utilities.ATLEAST_S) {
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
SystemUiProxy.INSTANCE.getNoCreate().startRecentsActivity(intent, options, mCallbacks);
if (Utilities.ATLEAST_U) {
SystemUiProxy.INSTANCE.getNoCreate().startRecentsActivity(intent, options, mCallbacks);
}
}
UI_HELPER_EXECUTOR.execute(() -> mCtx.startActivity(intent, options.toBundle()));
} else {
UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
.startRecentsActivity(intent, eventTime, mCallbacks, null, null));
@@ -140,6 +140,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
*/
private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[] {
TaskShortcutFactory.APP_INFO,
app.lawnchair.overview.TaskShortcutFactory.legacySplit,
TaskShortcutFactory.SPLIT_SELECT,
TaskShortcutFactory.PIN,
TaskShortcutFactory.INSTALL,
@@ -65,6 +65,8 @@ import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Represents a system shortcut that can be shown for a recent task. Appears as
* a single entry in
@@ -281,6 +283,7 @@ public interface TaskShortcutFactory {
@Override
public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
TaskIdAttributeContainer taskContainer) {
if (!LawnchairQuickstepCompat.ATLEAST_T) return null;
DeviceProfile deviceProfile = activity.getDeviceProfile();
final Task task = taskContainer.getTask();
final int intentFlags = task.key.baseIntent.getFlags();
@@ -51,6 +51,9 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* This class tracked the top-most task and some 'approximate' task history to allow faster
@@ -81,11 +84,14 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
@Override
public void onTaskRemoved(int taskId) {
if (!LawnchairQuickstepCompat.ATLEAST_T) return;
mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
}
@Override
public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
if (!LawnchairQuickstepCompat.ATLEAST_T) return;
mOrderedTaskList.removeIf(rto -> rto.taskId == taskInfo.taskId);
mOrderedTaskList.addFirst(taskInfo);
@@ -180,6 +186,14 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
*/
@UiThread
public CachedTaskInfo getCachedTopTask(boolean filterOnlyVisibleRecents) {
if (!LawnchairQuickstepCompat.ATLEAST_U) {
RunningTaskInfo task = TraceHelper.allowIpcs("getCachedTopTask.false", () ->
ActivityManagerWrapper.getInstance().getRunningTask(
false /* filterOnlyVisibleRecents */));
ArrayList<RunningTaskInfo> taskList = new ArrayList<>();
Collections.addAll(taskList, task);
return new CachedTaskInfo(taskList);
}
if (filterOnlyVisibleRecents) {
// Since we only know about the top most task, any filtering may not be applied on the
// cache. The second to top task may change while the top task is still the same.
@@ -240,7 +254,7 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
List<RunningTaskInfo> visibleNonExcludedTasks = mAllCachedTasks.stream()
.filter(t -> t.isVisible
&& (t.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)
.toList();
.collect(Collectors.toList());
return visibleNonExcludedTasks.isEmpty() ? null
: new CachedTaskInfo(visibleNonExcludedTasks);
}
@@ -88,6 +88,7 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.provider.RestoreDbTask;
@@ -148,6 +149,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import app.lawnchair.LawnchairApp;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Service connected by system-UI for handling touch interaction.
@@ -206,12 +208,16 @@ public class TouchInteractionService extends Service {
IDragAndDrop dragAndDrop = IDragAndDrop.Stub.asInterface(
bundle.getBinder(KEY_EXTRA_SHELL_DRAG_AND_DROP));
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
SystemUiProxy.INSTANCE.get(tis).setProxy(proxy, pip,
bubbles, splitscreen, onehanded, shellTransitions, startingWindow,
recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode,
unfoldTransition, dragAndDrop);
tis.initInputMonitor("TISBinder#onInitialize()");
tis.preloadOverview(true /* fromInit */);
try {
SystemUiProxy.INSTANCE.get(tis).setProxy(proxy, pip,
bubbles, splitscreen, onehanded, shellTransitions, startingWindow,
recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode,
unfoldTransition, dragAndDrop);
tis.initInputMonitor("TISBinder#onInitialize()");
tis.preloadOverview(true /* fromInit */);
} catch (Throwable t) {
// Ignore
}
}));
sIsInitialized = true;
}
@@ -219,7 +225,7 @@ public class TouchInteractionService extends Service {
@BinderThread
@Override
public void onTaskbarToggled() {
if (!FeatureFlags.ENABLE_KEYBOARD_TASKBAR_TOGGLE.get())
if (!FeatureFlags.ENABLE_KEYBOARD_TASKBAR_TOGGLE.get() || !LawnchairQuickstepCompat.ATLEAST_S)
return;
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
TaskbarActivityContext activityContext = tis.mTaskbarManager.getCurrentActivityContext();
@@ -394,7 +400,7 @@ public class TouchInteractionService extends Service {
@Nullable
public TaskbarManager getTaskbarManager() {
TouchInteractionService tis = mTis.get();
if (tis == null)
if (tis == null || !LawnchairQuickstepCompat.ATLEAST_S)
return null;
return tis.mTaskbarManager;
}
@@ -489,14 +495,16 @@ public class TouchInteractionService extends Service {
mMainChoreographer = Choreographer.getInstance();
mAM = ActivityManagerWrapper.getInstance();
mDeviceState = new RecentsAnimationDeviceState(this, true);
mTaskbarManager = new TaskbarManager(this);
mTaskbarManager = LawnchairQuickstepCompat.ATLEAST_S ? new TaskbarManager(this) : null;
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
BootAwarePreloader.start(this);
// Call runOnUserUnlocked() before any other callbacks to ensure everything is
// initialized.
LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked);
LockedUserState.get(this).runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
if (LawnchairQuickstepCompat.ATLEAST_S) {
LockedUserState.get(this).runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
}
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
sConnected = true;
}
@@ -520,7 +528,16 @@ public class TouchInteractionService extends Service {
return;
}
mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId());
if (LawnchairQuickstepCompat.ATLEAST_S) {
mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId());
} else {
if (!SystemUiProxy.INSTANCE.get(this).isActive()) {
return;
}
Bundle bundle = SystemUiProxy.INSTANCE.get(this).monitorGestureInput("swipe-up",
mDeviceState.getDisplayId());
mInputMonitorCompat = InputMonitorCompat.fromBundle(bundle, "extra_input_monitor");
}
mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
mMainChoreographer, this::onInputEvent);
@@ -542,8 +559,10 @@ public class TouchInteractionService extends Service {
mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
mOverviewCommandHelper = new OverviewCommandHelper(this,
mOverviewComponentObserver, mTaskAnimationManager);
mResetGestureInputConsumer = new ResetGestureInputConsumer(
mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
if (LawnchairQuickstepCompat.ATLEAST_S && mTaskbarManager != null) {
mResetGestureInputConsumer = new ResetGestureInputConsumer(
mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
}
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
mInputConsumer.registerInputConsumer();
onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
@@ -585,15 +604,17 @@ public class TouchInteractionService extends Service {
private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
AccessibilityManager am = getSystemService(AccessibilityManager.class);
if (isHomeAndOverviewSame) {
am.registerSystemAction(createAllAppsAction(), GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
} else {
am.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
if (LawnchairQuickstepCompat.ATLEAST_R) {
if (isHomeAndOverviewSame) {
am.registerSystemAction(createAllAppsAction(), GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
} else {
am.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
}
}
StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface()
.getCreatedActivity();
if (newOverviewActivity != null) {
if (newOverviewActivity != null && mTaskbarManager != null) {
mTaskbarManager.setActivity(newOverviewActivity);
}
mTISBinder.onOverviewTargetChange();
@@ -604,7 +625,7 @@ public class TouchInteractionService extends Service {
.setAction(INTENT_ACTION_ALL_APPS_TOGGLE);
final PendingIntent actionPendingIntent;
if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get() && mTaskbarManager != null) {
actionPendingIntent = new PendingIntent(new IIntentSender.Stub() {
@Override
public void send(int code, Intent intent, String resolvedType,
@@ -634,7 +655,9 @@ public class TouchInteractionService extends Service {
int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
mOverviewComponentObserver.onSystemUiStateChanged();
mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags);
if (mTaskbarManager != null) {
mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags);
}
int isShadeExpandedFlag = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
boolean wasExpanded = (lastSysUIFlags & isShadeExpandedFlag) != 0;
@@ -671,10 +694,14 @@ public class TouchInteractionService extends Service {
mDeviceState.destroy();
SystemUiProxy.INSTANCE.get(this).clearProxy();
getSystemService(AccessibilityManager.class)
.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
if (LawnchairQuickstepCompat.ATLEAST_R) {
getSystemService(AccessibilityManager.class)
.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
}
mTaskbarManager.destroy();
if (mTaskbarManager != null) {
mTaskbarManager.destroy();
}
sConnected = false;
super.onDestroy();
}
@@ -706,7 +733,7 @@ public class TouchInteractionService extends Service {
// Note this will create a new consumer every mouse click, as after ACTION_UP
// from the click
// an ACTION_HOVER_ENTER will fire as well.
boolean isHoverActionWithoutConsumer = event.isHoverEvent()
boolean isHoverActionWithoutConsumer = isHoverEvent(action)
&& (mUncheckedConsumer.getType() & TYPE_CURSOR_HOVER) == 0;
if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
mRotationTouchHelper.setOrientationTransformIfNeeded(event);
@@ -801,9 +828,15 @@ public class TouchInteractionService extends Service {
traceToken.close();
}
private boolean isHoverEvent(int action) {
return action == MotionEvent.ACTION_HOVER_ENTER
|| action == MotionEvent.ACTION_HOVER_MOVE
|| action == MotionEvent.ACTION_HOVER_EXIT;
}
// Talkback generates hover events on touch, which we do not want to consume.
private boolean isCursorHoverEvent(MotionEvent event) {
return event.isHoverEvent() && event.getSource() == InputDevice.SOURCE_MOUSE;
return isHoverEvent(event.getActionMasked()) && event.getSource() == InputDevice.SOURCE_MOUSE;
}
private InputConsumer tryCreateAssistantInputConsumer(
@@ -925,7 +958,7 @@ public class TouchInteractionService extends Service {
// If Taskbar is present, we listen for swipe or cursor hover events to unstash
// it.
TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
TaskbarActivityContext tac = mTaskbarManager != null ? mTaskbarManager.getCurrentActivityContext() : null;
if (tac != null && !(base instanceof AssistantInputConsumer)) {
// Present always on large screen or on small screen w/ flag
DeviceProfile dp = tac.getDeviceProfile();
@@ -25,6 +25,8 @@ import com.android.launcher3.Utilities;
import java.util.function.BooleanSupplier;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Utility class for helpful methods related to {@link View} objects.
*/
@@ -43,6 +45,9 @@ public class ViewUtils {
*/
public static boolean postFrameDrawn(
View view, Runnable onFinishRunnable, BooleanSupplier canceled) {
if (!LawnchairQuickstepCompat.ATLEAST_U) {
return new FrameHandlerVR(view, onFinishRunnable, canceled).schedule();
}
return new FrameHandler(view, onFinishRunnable, canceled).schedule();
}
@@ -129,4 +134,51 @@ public class ViewUtils {
}
}
}
private static class FrameHandlerVR implements HardwareRenderer.FrameDrawingCallback {
final ViewRootImpl mViewRoot;
final Runnable mFinishCallback;
final BooleanSupplier mCancelled;
final Handler mHandler;
int mDeferFrameCount = 1;
FrameHandlerVR(View view, Runnable finishCallback, BooleanSupplier cancelled) {
mViewRoot = view.getViewRootImpl();
mFinishCallback = finishCallback;
mCancelled = cancelled;
mHandler = new Handler();
}
@Override
public void onFrameDraw(long frame) {
Utilities.postAsyncCallback(mHandler, this::onFrame);
}
private void onFrame() {
if (mCancelled.getAsBoolean()) {
return;
}
if (mDeferFrameCount > 0) {
mDeferFrameCount--;
schedule();
return;
}
if (mFinishCallback != null) {
mFinishCallback.run();
}
}
private boolean schedule() {
if (mViewRoot != null && mViewRoot.getView() != null) {
mViewRoot.registerRtFrameCallback(this);
mViewRoot.getView().invalidate();
return true;
}
return false;
}
}
}
@@ -54,6 +54,7 @@ import com.android.internal.util.ScreenshotRequest;
import com.android.launcher3.BuildConfig;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.topjohnwu.superuser.Shell;
import java.io.File;
import java.io.FileOutputStream;
@@ -61,6 +62,8 @@ import java.io.IOException;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import app.lawnchair.compatlib.utils.BitmapUtil;
/**
* Utility class containing methods to help manage image actions such as sharing, cropping, and
* saving image.
@@ -78,16 +81,25 @@ public class ImageActionUtils {
*/
public static void saveScreenshot(SystemUiProxy systemUiProxy, Bitmap screenshot,
Rect screenshotBounds, Insets visibleInsets, Task.TaskKey task) {
ScreenshotRequest request =
new ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OVERVIEW)
.setTopComponent(task.sourceComponent)
.setTaskId(task.id)
.setUserId(task.userId)
.setBitmap(screenshot)
.setBoundsOnScreen(screenshotBounds)
.setInsets(visibleInsets)
.build();
systemUiProxy.takeScreenshot(request);
try {
ScreenshotRequest request =
new ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OVERVIEW)
.setTopComponent(task.sourceComponent)
.setTaskId(task.id)
.setUserId(task.userId)
.setBitmap(screenshot)
.setBoundsOnScreen(screenshotBounds)
.setInsets(visibleInsets)
.build();
systemUiProxy.takeScreenshot(request);
} catch (Throwable t) {
try {
systemUiProxy.handleImageBundleAsScreenshot(BitmapUtil.hardwareBitmapToBundle(screenshot),
screenshotBounds, visibleInsets, task);
} catch (Throwable ee) {
Shell.su("input keyevent 120").exec();
}
}
}
/**
@@ -107,6 +107,8 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Represent data needed for the transient state when user has selected one app for split screen
* and is in the process of either a) selecting a second app or b) exiting intention to invoke split
@@ -468,7 +470,7 @@ public class SplitSelectStateController {
final RemoteSplitLaunchTransitionRunner animationRunner =
new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
final RemoteTransition remoteTransition = LawnchairQuickstepCompat.getRemoteTransitionCompat().getRemoteTransition(animationRunner,
ActivityThread.currentActivityThread().getApplicationThread(),
"LaunchAppFullscreen");
InstanceId instanceId = LogUtils.getShellShareableInstanceId().first;
@@ -513,7 +515,7 @@ public class SplitSelectStateController {
@Nullable Consumer<Boolean> callback, String transitionName) {
final RemoteSplitLaunchTransitionRunner animationRunner =
new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
return new RemoteTransition(animationRunner,
return LawnchairQuickstepCompat.getRemoteTransitionCompat().getRemoteTransition(animationRunner,
ActivityThread.currentActivityThread().getApplicationThread(), transitionName);
}
@@ -20,6 +20,8 @@ import android.graphics.Rect;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import com.android.launcher3.Utilities;
/**
* Helper class for building a {@link Transaction}.
*/
@@ -103,7 +105,9 @@ public class SurfaceTransaction {
* @return this Builder
*/
public SurfaceProperties setShadowRadius(float radius) {
mTransaction.setShadowRadius(mSurface, radius);
if (Utilities.ATLEAST_R) {
mTransaction.setShadowRadius(mSurface, radius);
}
return this;
}
@@ -27,6 +27,8 @@ import android.view.ViewRootImpl;
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* Helper class to apply surface transactions in sync with RenderThread similar to
* android.view.SyncRtSurfaceTransactionApplier
@@ -112,7 +114,11 @@ public class SurfaceTransactionApplier extends ReleaseCheck {
.sendToTarget();
return;
}
mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
if (LawnchairQuickstepCompat.ATLEAST_S) {
mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
} else {
t.apply();
}
Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
.sendToTarget();
});
@@ -271,7 +271,11 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
final PictureInPictureSurfaceTransaction pipTx =
onAnimationUpdate(tx, new RectF(mDestinationBounds), END_PROGRESS);
pipTx.setShouldDisableCanAffectSystemUiFlags(true);
try {
pipTx.setShouldDisableCanAffectSystemUiFlags(true);
} catch (NoSuchMethodError error) {
Log.w(TAG, "not android 13 qpr1 : ", error);
}
return pipTx;
}
@@ -182,7 +182,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
public void setPreview(RemoteAnimationTarget runningTarget) {
setPreviewBounds(
runningTarget.startBounds == null
? runningTarget.screenSpaceBounds : runningTarget.startBounds,
? (Utilities.ATLEAST_R ? runningTarget.screenSpaceBounds : runningTarget.sourceContainerBounds) : runningTarget.startBounds,
runningTarget.contentInsets);
}
@@ -16,15 +16,20 @@
package com.android.quickstep.util;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import android.util.FloatProperty;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import com.android.app.animation.Interpolators;
import com.android.launcher3.Utilities;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import app.lawnchair.compat.LawnchairQuickstepCompat;
public class TransformParams {
@@ -162,7 +167,7 @@ public class TransformParams {
} else {
// Fade out translucent overlay.
// TODO(b/303351074): use app.isNotInRecents directly once it is fixed.
boolean isNotInRecents = app.taskInfo != null
boolean isNotInRecents = LawnchairQuickstepCompat.ATLEAST_S && app.taskInfo != null
&& (app.taskInfo.baseIntent.getFlags()
& FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
if (app.isTranslucent && isNotInRecents) {
@@ -219,6 +219,7 @@ import java.util.function.Consumer;
import java.util.stream.Collectors;
import app.lawnchair.LawnchairApp;
import app.lawnchair.compat.LawnchairQuickstepCompat;
import app.lawnchair.theme.color.ColorTokens;
import app.lawnchair.util.OverScrollerCompat;
@@ -5461,7 +5462,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
return;
}
final boolean sendUserLeaveHint = toRecents && shouldPip;
final boolean sendUserLeaveHint = toRecents && shouldPip && LawnchairQuickstepCompat.ATLEAST_S;
if (sendUserLeaveHint) {
// Notify the SysUI to use fade-in animation when entering PiP from live tile.
final SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(getContext());
@@ -5470,14 +5471,22 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// Transaction to hide the task to avoid flicker for entering PiP from
// split-screen.
// See also {@link AbsSwipeUpHandler#maybeFinishSwipeToHome}.
PictureInPictureSurfaceTransaction tx = new PictureInPictureSurfaceTransaction.Builder()
.setAlpha(0f)
.build();
tx.setShouldDisableCanAffectSystemUiFlags(false);
int[] taskIds = TopTaskTracker.INSTANCE.get(getContext()).getRunningSplitTaskIds();
for (int taskId : taskIds) {
mRecentsAnimationController.setFinishTaskTransaction(taskId,
tx, null /* overlay */);
try {
PictureInPictureSurfaceTransaction tx = new PictureInPictureSurfaceTransaction.Builder()
.setAlpha(0f)
.build();
try {
tx.setShouldDisableCanAffectSystemUiFlags(false);
} catch (NoSuchMethodError n) {
Log.w(TAG, "not Android 13 qpr1 : ", n);
}
int[] taskIds = TopTaskTracker.INSTANCE.get(getContext()).getRunningSplitTaskIds();
for (int taskId : taskIds) {
mRecentsAnimationController.setFinishTaskTransaction(taskId,
tx, null /* overlay */);
}
} catch (Throwable error) {
Log.w(TAG, "Failed PictureInPictureSurfaceTransaction: ", error);
}
}
mRecentsAnimationController.finish(toRecents, () -> {
@@ -122,6 +122,8 @@ import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
import app.lawnchair.compat.LawnchairQuickstepCompat;
/**
* A task in the Recents view.
*/
@@ -830,6 +832,7 @@ public class TaskView extends FrameLayout implements Reusable {
* second app. {@code false} otherwise
*/
protected boolean confirmSecondSplitSelectApp() {
if (!LawnchairQuickstepCompat.ATLEAST_T) return false;
int index = getLastSelectedChildTaskIndex();
TaskIdAttributeContainer container = mTaskIdAttributeContainer[index];
if (container != null) {
@@ -936,20 +939,25 @@ public class TaskView extends FrameLayout implements Reusable {
}
// Indicate success once the system has indicated that the transition has
// started
ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(getContext(), 0, 0,
ActivityOptions opts = LawnchairQuickstepCompat.ATLEAST_T ? ActivityOptions.makeCustomTaskAnimation(getContext(), 0, 0,
MAIN_EXECUTOR.getHandler(),
elapsedRealTime -> {
callback.accept(true);
},
elapsedRealTime -> {
failureListener.onTransitionFinished();
});
}) : makeCustomAnimation(getContext(), 0, 0,
() -> callback.accept(true), MAIN_EXECUTOR.getHandler());;
opts.setLaunchDisplayId(
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (isQuickswitch) {
opts.setFreezeRecentTasksReordering();
}
opts.setDisableStartingWindow(mSnapshotView.shouldShowSplashView());
try {
opts.setDisableStartingWindow(mSnapshotView.shouldShowSplashView());
} catch (Throwable t) {
// ignore
}
Task.TaskKey key = mTask.key;
UI_HELPER_EXECUTOR.execute(() -> {
if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) {
@@ -972,6 +980,9 @@ public class TaskView extends FrameLayout implements Reusable {
*/
private ActivityOptions makeCustomAnimation(Context context, int enterResId,
int exitResId, final Runnable callback, final Handler callbackHandler) {
if (!LawnchairQuickstepCompat.ATLEAST_T) {
return LawnchairQuickstepCompat.getActivityOptionsCompat().makeCustomAnimation(context, enterResId, exitResId, callback, callbackHandler);
}
return ActivityOptions.makeCustomTaskAnimation(context, enterResId, exitResId,
callbackHandler,
elapsedRealTime -> {
+7 -2
View File
@@ -58,7 +58,12 @@ include ':systemUILog'
include ':systemUIAnim'
include ':systemUnFold'
include ':systemUIViewCapture'
include ':compatLib'
include ':compatLibVR'
include ':compatLibVS'
include ':compatLib:compatLibVQ'
include ':compatLib:compatLibVR'
include ':compatLib:compatLibVS'
include ':compatLib:compatLibVT'
include ':compatLib:compatLibVU'
include ':baseline-profile'
@@ -1495,7 +1495,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
final Rect mPadding = new Rect();
AllAppsRecyclerView mRecyclerView;
AdapterHolder(int type, LawnchairAlphabeticalAppsList<T> appsList) {
AdapterHolder(int type, AlphabeticalAppsList<T> appsList) {
mType = type;
mAppsList = appsList;
mAdapter = createAdapter(mAppsList);
@@ -99,8 +99,6 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
var textColor = ColorTokens.ColorPrimary.resolveColor(getContext());
mIcon.setColorFilter(textColor);
mTextView.setTextColor(textColor);
DeviceProfile grid = BaseDraggingActivity.fromContext(getContext()).getDeviceProfile();
setInsets(grid.getInsets());
setInsets(mActivityContext.getDeviceProfile().getInsets());
mTextView.setText(R.string.work_apps_pause_btn_text);
@@ -139,6 +139,7 @@ public class SysUiScrim implements View.OnAttachStateChangeListener {
* Draw the top and bottom scrims
*/
public void draw(Canvas canvas) {
if (canvas == null) return;
if (!mHideSysUiScrim) {
if (mSysUiProgress.value <= 0) {
mAnimateScrimOnNextDraw = false;
@@ -156,10 +157,10 @@ public class SysUiScrim implements View.OnAttachStateChangeListener {
mAnimateScrimOnNextDraw = false;
}
if (mDrawTopScrim) {
if (mDrawTopScrim && mTopMaskBitmap != null) {
canvas.drawBitmap(mTopMaskBitmap, null, mTopMaskRect, mTopMaskPaint);
}
if (mDrawBottomScrim) {
if (mDrawBottomScrim && mBottomMaskBitmap != null) {
canvas.drawBitmap(mBottomMaskBitmap, null, mBottomMaskRect, mBottomMaskPaint);
}
}
@@ -31,6 +31,7 @@ import android.util.Log;
import androidx.annotation.FloatRange;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
@@ -238,7 +239,7 @@ public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
}
return;
} else if ((!mConfig.userControlled && animated && mConfig.targetState == state)
|| mState.shouldPreserveDataStateOnReapply()) {
|| (mState.shouldPreserveDataStateOnReapply() && Utilities.ATLEAST_U)) {
// We are running the same animation as requested, and/or target state should not be
// reset -- allow the current animation to complete instead of canceling it.
if (listener != null) {
@@ -24,7 +24,6 @@ import android.graphics.Matrix
import android.graphics.Path
import android.graphics.Rect
import android.graphics.RectF
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.RemoteException
@@ -523,6 +522,10 @@ class ActivityLaunchAnimator(
}
}
fun onAnimationCancelled(isKeyguardOccluded: Boolean) {
onAnimationCancelled()
}
@BinderThread
override fun onAnimationCancelled() {
val delegate = delegate
@@ -686,11 +689,12 @@ class ActivityLaunchAnimator(
// instead of recomputing isExpandingFullyAbove here.
val isExpandingFullyAbove =
launchAnimator.isExpandingFullyAbove(controller.launchContainer, endState)
val windowCornerRadius = getWindowCornerRadius()
val endRadius =
if (isExpandingFullyAbove) {
// Most of the time, expanding fully above the root view means expanding in full
// screen.
ScreenDecorationsUtils.getWindowCornerRadius(context)
windowCornerRadius
} else {
// This usually means we are in split screen mode, so 2 out of 4 corners will
// have
@@ -758,6 +762,15 @@ class ActivityLaunchAnimator(
)
}
private fun getWindowCornerRadius() : Float {
return try {
ScreenDecorationsUtils.getWindowCornerRadius(context)
} catch (t: Throwable) {
0f
}
}
private fun applyStateToWindow(
window: RemoteAnimationTarget,
state: LaunchAnimator.State,
@@ -1,5 +1,6 @@
package com.android.systemui.animation
import android.os.Build
import android.view.View
import android.window.SurfaceSyncGroup
@@ -28,11 +29,13 @@ object ViewRootSync {
return
}
val syncGroup = SurfaceSyncGroup("SysUIAnimation")
syncGroup.addSyncCompleteCallback(view.context.mainExecutor) { then() }
syncGroup.add(view.rootSurfaceControl, null /* runnable */)
syncGroup.add(otherView.rootSurfaceControl, null /* runnable */)
syncGroup.markSyncReady()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
val syncGroup = SurfaceSyncGroup("SysUIAnimation")
syncGroup.addSyncCompleteCallback(view.context.mainExecutor) { then() }
syncGroup.add(view.rootSurfaceControl, null /* runnable */)
syncGroup.add(otherView.rootSurfaceControl, null /* runnable */)
syncGroup.markSyncReady()
}
}
/** A Java-friendly API for [synchronizeNextDraw]. */
@@ -0,0 +1,53 @@
package app.lawnchair.compat
import android.os.Build
import app.lawnchair.compatlib.ActivityManagerCompat
import app.lawnchair.compatlib.ActivityOptionsCompat
import app.lawnchair.compatlib.QuickstepCompatFactory
import app.lawnchair.compatlib.RemoteTransitionCompat
import app.lawnchair.compatlib.eleven.QuickstepCompatFactoryVR
import app.lawnchair.compatlib.fourteen.QuickstepCompatFactoryVU
import app.lawnchair.compatlib.ten.QuickstepCompatFactoryVQ
import app.lawnchair.compatlib.thirteen.QuickstepCompatFactoryVT
import app.lawnchair.compatlib.twelve.QuickstepCompatFactoryVS
object LawnchairQuickstepCompat {
@JvmField
val ATLEAST_Q: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
@JvmField
val ATLEAST_R: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
@JvmField
val ATLEAST_S: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
@JvmField
val ATLEAST_T: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
@JvmField
val ATLEAST_U: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
@JvmStatic
val factory: QuickstepCompatFactory = if (ATLEAST_U) {
QuickstepCompatFactoryVU()
} else if (ATLEAST_T) {
QuickstepCompatFactoryVT()
} else if (ATLEAST_S) {
QuickstepCompatFactoryVS()
} else if (ATLEAST_R) {
QuickstepCompatFactoryVR()
} else {
QuickstepCompatFactoryVQ()
}
@JvmStatic
val activityManagerCompat: ActivityManagerCompat = factory.activityManagerCompat
@JvmStatic
val activityOptionsCompat: ActivityOptionsCompat = factory.activityOptionsCompat
@JvmStatic
val remoteTransitionCompat: RemoteTransitionCompat = factory.remoteTransitionCompat
}
@@ -61,6 +61,16 @@ interface ISystemUiProxy {
*/
oneway void onAssistantGestureCompletion(float velocity) = 18;
/**
* Get the secondary split screen app's rectangle when not minimized.
*/
Rect getNonMinimizedSplitScreenSecondaryBounds() = 7;
/**
* Creates a new gesture monitor
*/
Bundle monitorGestureInput(String name, int displayId) = 14;
/**
* Start the assistant.
*/
@@ -90,6 +100,28 @@ interface ISystemUiProxy {
*/
oneway void stopScreenPinning() = 17;
/**
* Handle the provided image as if it was a screenshot.
*
* Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask
* @deprecated
*/
void handleImageAsScreenshot(in Bitmap screenImage, in Rect locationInScreen,
in Insets visibleInsets, int taskId) = 21;
/**
* Sets the split-screen divider minimized state
*/
void setSplitScreenMinimized(boolean minimized) = 22;
/*
* Notifies that the swipe-to-home (recents animation) is finished.
*/
void notifySwipeToHomeFinished() = 23;
/** Notifies that a swipe-up gesture has started */
void notifySwipeUpGestureStarted() = 46;
/**
* Notifies that quickstep will switch to a new task
* @param rotation indicates which Surface.Rotation the gesture was started in
@@ -134,6 +166,12 @@ interface ISystemUiProxy {
*/
oneway void takeScreenshot(in ScreenshotRequest request) = 51;
/**
* 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;
/**
* Dispatches trackpad status bar motion event to the notification shade. Currently these events
* are from the input monitor in {@link TouchInteractionService}. This is different from
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff. Show more