Android近期任务列表Recent List(Recents Screen)的实现方式

本文深入解析了Android系统中RecentList的实现原理,包括其与AMS的通信机制、RecentList的获取与删除方法等内容。

一、明确android的近期任务是什么:

我们的手机下方一般有三个键,一个是返回键,中间的是home键,另一个是RecentList键,也就是最近浏览记录的记录键,这个的实现在4.0及以上版本使用,android 5.0(api 21)之后,为了系统的安全性,不再允许被第三方开发人员使用,也就是api中不再被使用。但是,为了向前的兼容性,还是允许使用获得近期浏览记录的api,只是只能获得部分不敏感数据。

它的样子:


就是这样的一个列表,具体实现的原理,这里简单讲解一下:

我们的桌面简单讲就是一个launch,桌面上的每一个图标代表一个application,每次启动一个app,都会往系统的一个叫做RecentTask的栈中传入一个task(任务),当我们退出app的时候,不论home退出还是按返回键退出,它在离开当前的显示界面,也就是不在onResume状态,就是不在前台的时候,系统都会截图离开时候的状态,并记录下当前的状态信息,包括具体的Activity,以便于从后台直接调到前台来使用。这个Task栈保存的是Activity的活动状态,但是不全是一个app的,而是不同app的。

(之所以要将我们要清楚这个是什么,在于我们要认识到android系统常用的几种状态:process、task和app。因为我在开发的初期阶段,认为这是一个running application列表,一直在调用系统中运行的process,所以走偏了很久。)

具体详细介绍请查阅官方文档


二、AMS与ActivityManager的通信原理:

android系统的所以服务、进程等管理都是通过SysytenService来实现的,而管理是通过ActivityManager.java。关于它的含义,上篇博客中已经做了介绍,ActivityManager只是一个传递信息的接口,它的目的是传递需要的东西给ActivityManagerService,后者才是真正实现的方法。

关于AMS通信的原理,我这里画了一个图:


ActivityManagerService与ActivityManager之间的通信是通过Binder机制来完成的,具体如何实现的呢:

ActivityManagerNative中实现的代码是运行在Android应用程序的进程空间中的,可直接使用的对象,Intent会由应用程序通过这个类将方法对应的Binder命令发送出去,而它本身继承了Binder类,并实现了ActivityManager接口,源码如图:


所以它可以获得ActivityManager关于内存、任务等内部信息,而ActivityManagerService作为ActivityManagerNative的子类,自然也就可以获得这些信息。

例如:

ActivityManager中的方法getAppTasks()方法:


我们会发现这些方法都会先调用ActivityManagerNative的getDefault()方法来获得ActivityManager的代理接口对象。那么getDefault()方法又是什么呢?

我们打开这个方法会发现,如图:



我们会发现,它主要是调用SystemService对象,并进行它的方法调用,比如它的getService(“activity”)的调用。

而关于ServiceManager类,它是系统最最基本的一个管理类,所有的服务都是通过getService方法得到的,这里的AMS和ActivityManager的通信,就是通过得到相关的Binder来实现的。

在得到了Binder之后,就可以通过ActivityManagerProxy类来进行与AMS通信,ActivityManagerProxy继承了ActivityManager,可以看做是ActivityManager的一个代理。由此就可以通过transact传递数据给ActivityManagerService(AMS)来进行具体的处理了,处理完之后再打包成相应的Binder返回给ActivityManager。


三、RecentList的获取和删除功能的实现。

1.RecentList列表的获取:

使用的方法是ActivityManager的getRecentTasks()方法,它有两个参数,一个是最大获取的数量值,另一个是flag标志位,具体实现代码:

public static void reloadButtons(Activity activity, List<HashMap<String, Object>> appInfos,
                                     int appNumber) {
        int MAX_RECENT_TASKS = appNumber; // allow for some discards
        int repeatCount = appNumber;// 保证上面两个值相等,设定存放的程序个数

		/* 每次加载必须清空list中的内容 */
        appInfos.removeAll(appInfos);

        // 得到包管理器和activity管理器
        final Context context = activity.getApplication();
        final PackageManager pm = context.getPackageManager();
        final ActivityManager am = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);

        // 从ActivityManager中取出用户最近launch过的 MAX_RECENT_TASKS + 1 个,以从早到晚的时间排序,
        // 注意这个 0x0002,它的值在launcher中是用ActivityManager.RECENT_IGNORE_UNAVAILABLE
        // 但是这是一个隐藏域,因此我把它的值直接拷贝到这里
        final List<ActivityManager.RecentTaskInfo> recentTasks = am
                .getRecentTasks(MAX_RECENT_TASKS + 1, 0x0002);
                //.getRecentTasks(MAX_RECENT_TASKS + 1, 8);


        // 这个activity的信息是我们的launcher
        ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(
                Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);

        int numTasks = recentTasks.size();
        for (int i = 1; i < numTasks && (i < MAX_RECENT_TASKS); i++) {
            HashMap<String, Object> singleAppInfo = new HashMap<String, Object>();// 当个启动过的应用程序的信息
            final ActivityManager.RecentTaskInfo info = recentTasks.get(i);

            Intent intent = new Intent(info.baseIntent);
            if (info.origActivity != null) {
                intent.setComponent(info.origActivity);
            }
            /**
             * 如果找到是launcher,直接continue,后面的appInfos.add操作就不会发生了
             */
            if (homeInfo != null) {
                if (homeInfo.packageName.equals(intent.getComponent()
                        .getPackageName())
                        && homeInfo.name.equals(intent.getComponent()
                        .getClassName())) {
                    MAX_RECENT_TASKS = MAX_RECENT_TASKS + 1;
                    continue;
                }
            }
            // 设置intent的启动方式为 创建新task()【并不一定会创建】
            intent.setFlags((intent.getFlags() & ~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
                    | Intent.FLAG_ACTIVITY_NEW_TASK);
            // 获取指定应用程序activity的信息(按我的理解是:某一个应用程序的最后一个在前台出现过的activity。)
            final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
            if (resolveInfo != null) {
                final ActivityInfo activityInfo = resolveInfo.activityInfo;
                final String title = activityInfo.loadLabel(pm).toString();
                Drawable icon = activityInfo.loadIcon(pm);

                //&& info.id != -1
                if (title != null && title.length() > 0 && icon != null ) {
                    singleAppInfo.put("title", title);
                    singleAppInfo.put("icon", icon);
                    singleAppInfo.put("tag", intent);
                    singleAppInfo.put("packageName", activityInfo.packageName);
                    singleAppInfo.put("id", info.persistentId);
                    appInfos.add(singleAppInfo);
                }
            }
        }
        MAX_RECENT_TASKS = repeatCount;
    }
(代码原文博客: http://blog.youkuaiyun.com/benyoulai5/article/details/48447079

2.删除具体某个应用的记录的方法:removeTask(),这里传入的参数是int型的id,这个id在RecentTaskInfo中指的是persistentId

关于removeTask方法,这个方法只能在有系统权限下才能使用,官方API中是没有的。

如图:


(这是源码中的解释。在此之前,我尝试了很多种方法去解决删除task栈中的元素方法,但是发现没有removeTask方法,而通过停止运行process或者强制结束运行应用的方法都无法删除RecentList中的数据,因为它只是一个记录栈,而且属于系统级别的Task栈,必须获得系统的这个数据栈才能将它删除掉。)

另一种获得removeTask的方法是反射,我尝试了一下网上的方法,并不行,因为反射我也不会,所以不确定是个人问题还是方法的问题。

我这里实现的方式是导入系统的架包,直接获取的方法,如图:


(关于引入系统架包与本地SDK冲突的解决方式,比较简单的方式是更改项目下的编译时的获取api的加载顺序,以后我会专门写一个博客详细讲解。)

/******************************************************************************** ** Copyright (C), 2023-2123, Oplus Mobile Comm Corp., Ltd ** All rights reserved. ** ** File: - OplusInterruptTransitionManager.java ** Description: ** Manager of interrupt transition ** ** Version: 1.0 ** Date: 2024-02-04 ** Author: LiYichen@ANDROID.WMS ** TAG: OPLUS_FEATURE_INTERRUPT_TRANSITION ** ------------------------------- Revision History: ---------------------------- ** <author> <data> <version> <desc> ** ------------------------------------------------------------------------------ ** LiYichen@ANDROID.WMS 2024-02-04 1.0 Create this module ********************************************************************************/ package com.oplus.transition; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityThread; import android.content.Context; import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.os.SystemProperties; import android.util.ArrayMap; import android.util.Log; import android.view.Surface; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.animation.Animation; import android.window.RemoteTransition; import android.view.WindowManager; import android.window.TransitionInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.recents.RecentsTransitionHandler; //import com.android.wm.shell.transition.RecentsMixedTransition; import com.android.wm.shell.transition.DefaultTransitionHandler; import com.android.wm.shell.transition.RemoteTransitionHandler; import android.window.RemoteTransition; import com.android.wm.shell.transition.TransitionAnimationUtil; import com.android.wm.shell.transition.TransitionLog; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.util.ReflectionUtils; import com.android.wm.shell.shared.TransitionUtil; import android.view.IRecentsAnimationController; import android.window.WindowOrganizer; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.TransitionInfo.FLAG_NO_ANIMATION; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; import static android.window.TransitionInfo.FLAG_TRANSLUCENT; import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP; import static android.window.TransitionInfo.FLAG_NONE; import static com.android.wm.shell.shared.TransitionUtil.isClosingType; import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet; import static com.android.wm.shell.shared.TransitionUtil.isOpeningType; import static com.oplus.content.OplusIntent.OPLUS_FLAG_POCKET_STUDIO_CANVAS; import static com.oplus.wrapper.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; import com.oplus.content.OplusFeatureConfigManager; import com.oplus.splitscreen.ReflectionHelper; import com.oplus.uifirst.OplusUIFirstManager; import java.util.ArrayList; import java.util.List; import java.lang.reflect.Field; import java.lang.reflect.Method; public class OplusInterruptTransitionManager { public static final String TAG = "OplusInterruptTransitionManager"; public static final String OPLUS_FEATURE_INTERRUPT_TRANSITION = "oplus.software.support_blockable_animation"; public static final boolean DEBUG_INTERRUPT_TRANSITION_PROP = SystemProperties.getBoolean( "persist.wm.debug.interrupt_transition", false); public static final boolean ENABLE_INTERRUPT_TRANSITION = DEBUG_INTERRUPT_TRANSITION_PROP || OplusFeatureConfigManager.getInstance().hasFeature(OPLUS_FEATURE_INTERRUPT_TRANSITION); private static final String EXT = "mExt"; private static final String GET_EXTENDED_INFO = "getExtendedInfo"; private static final String SET_RECENTS_CONTROLLER = "setRecentsController"; private static final String TASKFRAGMENT = "TaskFragment"; private static final String GET_PARENT_LEASH_FOR_BG_COLOR = "getParentLeashForBgColor"; private static final String SET_IS_BAL_ALLOW = "setIsBalAllow"; private static final String SET_IS_REMOTE_FROM_LAUNCHER = "setIsRemoteFromLauncher"; private static final String IS_OPLUS_ANIM_RES = "isOplusAnimRes"; private static final String GET_AVOID_INTERCEPT_KEY_EVENT_TO_HOME = "getAvoidInterceptKeyEventToHome"; private static final String SET_MERGE_BACK_ANIMATION_TO_RECENTS = "setMergeBackAnimationToRecents"; private static final String KEY_HAS_FIX_ROTATION_LEASH = "has-fix-rotation-leash"; private static final String GET_TASK_NOT_IN_RECENT_ON_EXTINFO = "getTaskNotInRecent"; private static final String SET_IS_TASK_NOT_IN_RECENTS = "setIsTaskNotInRecents"; private static final String GET_IS_TASK_NOT_IN_RECENTS = "getIsTaskNotInRecents"; private static final String GET_REQUEST_TRANSITION_TASK_ID = "getRequestTransitionTaskId"; private static final String SET_REQUEST_TRANSITION_TASK_ID = "setRequestTransitionTaskId"; private static final String GET_IS_FROM_HOME = "getIsFromHome"; private static final String GET_IS_BAL_ALLOW = "getIsBalAllow"; private static final String GET_IS_FROM_OVERLAY = "getIsFromOverlay"; private static final String IS_ASSIST_SCREEN_SHOWING = "isAssistScreenShowing"; private static final String PKG_LAUNCHER = "com.android.launcher"; private static final int OPLUS_MIRAGE_DISPLAY = 10000; private static final int OPLUS_MIRAGE_TVDISPLAY = 2020; public static final int INTERRUPT_TRACK = 10; private static final int STATE_NEW_TASK = 1; private static volatile OplusInterruptTransitionManager sInstance; private Transitions mTransitions; private boolean mRemoteInterrupt; private boolean mRecentFinishToHome; private long mRecentFinishSeqId; private boolean mIsLandScapeExitScene; private IBinder mRemoteTransitionToken; public static OplusInterruptTransitionManager getInstance() { if (sInstance == null) { synchronized (OplusInterruptTransitionManager.class) { if (sInstance == null) { sInstance = new OplusInterruptTransitionManager(); } } } return sInstance; } public void init(Transitions transitions) { mTransitions = transitions; } public boolean isRemoteInterrupt() { if (!ENABLE_INTERRUPT_TRANSITION) { return false; } return mRemoteInterrupt; } public void setInterrupt(boolean interrupt) { mRemoteInterrupt = interrupt; } public void resetRemoteInterrupt() { if (isRemoteInterrupt()) { setInterrupt(false); } } public void setRecentFinishToHome(boolean toHome) { mRecentFinishToHome = toHome; } public boolean isRecentFinishToHome() { return mRecentFinishToHome; } public void continueRecents(Transitions.ActiveTransition playing, Transitions.ActiveTransition ready, RecentsTransitionHandler recentsHandler, WindowOrganizer organizer) { if (recentsHandler == null) { return; } RecentsTransitionHandler.RecentsController recentsController = recentsHandler.getRecentController(ready.mToken); TransitionLog.always("continueRecent track.mActiveTransition: " + ready + ", controller: " + recentsController); if (recentsController != null) { ArrayList<Integer> readyTaskIds = getChangeTaskIds(ready.mInfo); recentsController.setTmpRemote(playing); TransitionInfo remoteInfo = recentsController.getTmpRemote().mInfo; for (TransitionInfo.Change change : remoteInfo.getChanges()) { // avoid flick when recent finish, because remote will apply earlier if (change == null || change.getLeash() == null || !change.getLeash().isValid()) { continue; } if ((change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) && !change.getLeash().toString().contains(TASKFRAGMENT)) { recentsController.getTmpRemote().mFinishT.hide(change.getLeash()); if (change.getTaskInfo() != null && change.getTaskInfo().topActivityType != ACTIVITY_TYPE_HOME && !readyTaskIds.contains(change.getTaskInfo().taskId)) { ready.mStartT.hide(change.getLeash()); TransitionLog.always("The change: " + change + " of remote transiton " + "don't participate recents, so hide task surface"); } } } } setInterrupt(true); notifyRemoteInterrupt(playing.mToken, ready.mToken, organizer); } private ArrayList<Integer> getChangeTaskIds(TransitionInfo info) { ArrayList<Integer> taskIds = new ArrayList<>(); for (TransitionInfo.Change change : info.getChanges()) { if (change.getTaskInfo() != null) { taskIds.add(change.getTaskInfo().taskId); } } return taskIds; } public void finishTmpRemoteTransition(Transitions.ActiveTransition active, SurfaceControl.Transaction finishT, RecentsTransitionHandler recentsTransitionHandler, WindowContainerTransaction wct, ArrayList<Transitions.TransitionObserver> observers, ShellTaskOrganizer organizer) { if (recentsTransitionHandler == null || recentsTransitionHandler.getRecentController(active.mToken) == null) { return; } Transitions.ActiveTransition tmpRemote = recentsTransitionHandler.getRecentController(active.mToken).getTmpRemote(); if (tmpRemote == null) { return; } boolean isRecentToHome = OplusRemoteInterruptManager.ReflectionHelper.isRecentFinishToHome(wct); long seqId = OplusRemoteInterruptManager.ReflectionHelper.getRecentFinishSeq(wct); TransitionLog.always("finishTmpRemoteTransition " + tmpRemote + ", wct=" + wct + ", isRecentToHome=" + isRecentToHome + ", seqId=" + seqId); for (int i = 0; i < observers.size(); ++i) { observers.get(i).onTransitionFinished(tmpRemote.mToken, tmpRemote.mAborted); } if (tmpRemote.mMerged != null) { for (int iM = 0; iM < tmpRemote.mMerged.size(); ++iM) { final Transitions.ActiveTransition toMerge = tmpRemote.mMerged.get(iM); if (toMerge.mStartT != null) { finishT.merge(toMerge.mStartT); } if (toMerge.mFinishT != null) { finishT.merge(toMerge.mFinishT); } } } WindowContainerTransaction tmpWCT = new WindowContainerTransaction(); OplusRemoteInterruptManager.ReflectionHelper.recordRecentFinishState(tmpWCT, isRecentToHome, seqId); tmpRemote.mInfo.releaseAnimSurfaces(); //#ifdef OPLUS_TRANSITION_BUGFIX 7004238 //#songchunlong@ANDROID.WMS, 2024/03/06, Modify for finishTransition async ux binder //Jun.Gao@ANDROID.WMS, 2024/10/29, Modify for using sdk interface set async binder ux OplusUIFirstManager.getInstance().setBinderThreadUxFlag(-1, 1); //#endif /* OPLUS_TRANSITION_BUGFIX */ organizer.finishTransition(tmpRemote.mToken, tmpWCT); if (tmpRemote.mMerged != null) { for (int iM = 0; iM < tmpRemote.mMerged.size(); ++iM) { Transitions.ActiveTransition merged = tmpRemote.mMerged.get(iM); organizer.finishTransition(merged.mToken, tmpWCT /* wct */); merged.mInfo.releaseAnimSurfaces(); } tmpRemote.mMerged.clear(); } recentsTransitionHandler.getRecentController(active.mToken).setTmpRemote(null); } public void reorderHomeWhenFinish(int state, WindowContainerToken launcherTask, int track, WindowContainerTransaction wct) { if (!ENABLE_INTERRUPT_TRANSITION) { return; } setRecentFinishToHome(true); if (state == STATE_NEW_TASK && launcherTask != null && !nextWillCloseLauncher(track)) { TransitionLog.always("recents reorderHomeWhenFinish"); wct.reorder(launcherTask, true /* toTop */); } } public boolean showOpenTaskInFinishIfNeeded(int trackId, WindowContainerToken openTaskToken, IBinder transitionTokenMergeRecents) { if (openTaskToken == null || transitionTokenMergeRecents == null) { return true; } Transitions.ActiveTransition readyTransition = mTransitions.nextReadyTransition(trackId); if (readyTransition != null && readyTransition.mInfo != null && readyTransition.mToken.equals(transitionTokenMergeRecents)) { boolean remoteFromLaunch = mTransitions.isRemoteOpenRequestedFrom(readyTransition.mToken, "QuickstepLaunch"); TransitionInfo readyInfo = readyTransition.mInfo; if (remoteFromLaunch && readyInfo.getChanges().stream().anyMatch(change -> openTaskToken.equals(change.getContainer()))) { TransitionLog.always("readyTransiton: " + readyTransition + " don't merge into recents, but task:" + openTaskToken + " add to openingtask, so don't show it when recents finish"); return false; } } return true; } private boolean nextWillCloseLauncher(int trackId) { if (trackId < 0) { return false; } Transitions.ActiveTransition ready = mTransitions.nextReadyTransition(trackId); if (ready != null && ready.mInfo != null) { TransitionInfo info = ready.mInfo; List<TransitionInfo.Change> changes = info.getChanges(); // #ifdef OPLUS_FEATURE_INTERRUPT_TRANSITION // Qin.Ding@ANDROID.WMS 2024/05/27, add for almid:7350478, 7367404, 7360883 if (changes.size() <= 2 && info.getType() == TRANSIT_OPEN) { TransitionInfo.Change change = changes.get(0); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo != null && taskInfo.getActivityType() != ACTIVITY_TYPE_HOME && !TransitionUtil.isClosingType(change.getMode()) && !change.hasFlags(FLAG_TRANSLUCENT)) { boolean isFromOverlay = OplusTransitionReflectionHelper.methodInvokeOnExt(info, GET_IS_FROM_OVERLAY, null); if ((changes.size() == 2 && isFromOverlay) || changes.size() == 1) { TransitionLog.always("nextWillCloseLauncher, Prevent reorder launcherTask, changes.size=" + changes.size()); return true; } } } // #endif /*OPLUS_FEATURE_INTERRUPT_TRANSITION*/ for (int i = 0; i < changes.size(); i ++) { TransitionInfo.Change change = changes.get(i); if (change.getTaskInfo() != null && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME && TransitionUtil.isClosingType(change.getMode())) { return true; } } } return false; } // #ifdef OPLUS_FEATURE_ANIMATION // Qin.Ding@ANDROID.WMS 2024/07/06, Modify for almid:7502858, 7532587 public boolean skipMergeIntoRecentsIfNeed(TransitionInfo info, IBinder mergedToken, WindowContainerToken recentsTask, RecentsTransitionHandler.RecentsController controller) { //#ifdef OPLUS_FEATURE_INTERRUPT_TRANSITION //LiYichen@ANDROID.WMS 2024/4/19, Add for interrupt transition if (null == recentsTask) { controller.cancel("cancel_by_interrupt"); TransitionLog.always(TAG + " skip merge into recents, when recentsTask is null"); return true; } //#endif /*OPLUS_FEATURE_INTERRUPT_TRANSITION*/ boolean isRemoteOpenFromSysUI = mTransitions.isRemoteOpenRequestedFrom(mergedToken, "SysUIPluginLaunch"); if (isRemoteOpenFromSysUI) { TransitionLog.always(TAG + " skip merge into recents, when remote open debugname is SysUIPluginLaunch"); return true; } if (OplusTransitionReflectionHelper.methodInvokeOnExt(info, GET_IS_FROM_OVERLAY, null)) { TransitionLog.always(TAG + " skip merge into recents, when open from overlay"); return true; } //add for ps 7822096 if (skipMergeIntoRecentsForCanvas(info, controller)) { controller.cancel("cancel_by_canvas"); TransitionLog.always(TAG + " skip merge into recents, when canvas switch"); return true; } return false; } // #endif /* OPLUS_FEATURE_ANIMATION */ private boolean skipMergeIntoRecentsForCanvas(TransitionInfo mergeInfo, RecentsTransitionHandler.RecentsController controller) { TransitionInfo playingInfo = (controller == null) ? null : controller.getPlayingTransitionInfo(); if (controller == null || mergeInfo == null || playingInfo == null) { return false; } boolean isCanvasSwitch = false; boolean hasToFrontCanvasInMergeInfo = false; boolean hasToBackHomeInMergeInfo = false; boolean hasToBackCanvasInPlayingInfo = false; boolean hasToFrontHomeInPlayingInfo = false; boolean hasSameEmbeddedChildren = false; int mergeCanvasTaskId = -1; int playingCanvasTaskId = -1; List<Integer> mergeTaskIdList = null; List<Integer> playingTaskIdList = null; for (int i = 0; i < mergeInfo.getChanges().size(); ++i) { final TransitionInfo.Change change = mergeInfo.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo == null) { continue; } if (isCanvasTask(taskInfo) && change.getMode() == WindowManager.TRANSIT_TO_FRONT) { mergeCanvasTaskId = taskInfo.taskId; hasToFrontCanvasInMergeInfo = true; mergeTaskIdList = ReflectionHelper.FlexibleWindowManager_getEmbeddedChildren(taskInfo.taskId); } if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME && change.getMode() == TRANSIT_TO_BACK) { hasToBackHomeInMergeInfo = true; } } for (int i = 0; i < playingInfo.getChanges().size(); ++i) { final TransitionInfo.Change change = playingInfo.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo == null) { continue; } if (isCanvasTask(taskInfo) && change.getMode() == WindowManager.TRANSIT_TO_BACK) { playingCanvasTaskId = taskInfo.taskId; hasToBackCanvasInPlayingInfo = true; playingTaskIdList = ReflectionHelper.FlexibleWindowManager_getEmbeddedChildren(taskInfo.taskId); } if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME && change.getMode() == TRANSIT_TO_FRONT) { hasToFrontHomeInPlayingInfo = true; } } if (mergeTaskIdList == null || mergeTaskIdList.isEmpty() || playingTaskIdList == null || playingTaskIdList.isEmpty()) { return false; } if (mergeCanvasTaskId == playingCanvasTaskId || mergeCanvasTaskId == -1 || playingCanvasTaskId == -1) { return false; } isCanvasSwitch = hasToFrontCanvasInMergeInfo && hasToBackHomeInMergeInfo && hasToBackCanvasInPlayingInfo && hasToFrontHomeInPlayingInfo; hasSameEmbeddedChildren = mergeTaskIdList.retainAll(playingTaskIdList); return isCanvasSwitch && hasSameEmbeddedChildren; } private boolean isCanvasTask(@NonNull ActivityManager.RunningTaskInfo task) { return task != null && (TransitionAnimationUtil.getOplusFlags( task.baseIntent) & OPLUS_FLAG_POCKET_STUDIO_CANVAS) != 0; } public boolean ifMergeIntoRemote(TransitionInfo info, SurfaceControl.Transaction t, Transitions.TransitionFinishCallback finishCallback, boolean mergedIsNotRemote) { if (!ENABLE_INTERRUPT_TRANSITION) { return false; } if (normalTaskLevelSamePkgName(info)) { // merged into remote TransitionLog.always(TAG + " transition " + info.getDebugId() + "have same packagename and " + "only normal task level, merge into remote."); finishCallback.onTransitionFinished(null); return true; } for (TransitionInfo.Change change : info.getChanges()) { // if changes have a task, skip if (change.getTaskInfo() != null) { return false; } } if (isPureLauncherTransition(info)) { return false; } if (isLargeSmallScreenSwitchAnim(info)) { TransitionLog.always(TAG + " transition " + info.getDebugId() + " isLargeSmallScreenSwitchAnim, do not merge into remote."); return false; } boolean needMergeRemote = false; for (TransitionInfo.Change change : info.getChanges()) { // if changes are activity, need to be merged into remote if (change.getTaskInfo() == null && !change.hasFlags(TransitionInfo.FLAG_IS_WALLPAPER)) { needMergeRemote = true; } // update alpha after setupStartState if (TransitionUtil.isOpeningType(info.getType()) && TransitionUtil.isOpeningType(change.getMode())) { t.setAlpha(change.getLeash(), 1); } } if (needMergeRemote && mergedIsNotRemote) { // apply startT in advance t.apply(); t.clear(); // merged into remote TransitionLog.debug("remote mergeAnimation, " + info.getDebugId() + " merged into remote"); finishCallback.onTransitionFinished(null); return true; } return false; } private boolean normalTaskLevelSamePkgName(TransitionInfo info) { if (info == null) { return false; } boolean hasSamePackage = true; String taskPackageName = null; boolean hasNoAnimFlag = false; boolean hasNoneFlagInOpenType = false; for (TransitionInfo.Change change : info.getChanges()) { if (change.getTaskInfo() == null) { return false; } if (change.getTaskInfo().realActivity != null) { if (change.hasFlags(FLAG_NO_ANIMATION)) { hasNoAnimFlag = true; } if (info.getType() == TRANSIT_OPEN && change.getMode() == TRANSIT_CLOSE && change.getFlags() == FLAG_NONE) { hasNoneFlagInOpenType = true; } String changePackageName = change.getTaskInfo().realActivity.getPackageName(); if (PKG_LAUNCHER.equals(changePackageName)) { return false; } if (taskPackageName == null) { taskPackageName = changePackageName; } else if (!taskPackageName.equals(changePackageName)) { hasSamePackage = false; } } } return hasSamePackage && (hasNoAnimFlag || hasNoneFlagInOpenType); } public static boolean isLargeSmallScreenSwitchAnim(TransitionInfo info) { if (info.getType() == TRANSIT_CHANGE) { for (TransitionInfo.Change change : info.getChanges()) { if (change.hasFlags(FLAG_IS_DISPLAY) && change.getStartRotation() == change.getEndRotation()) { return true; } } } return false; } public boolean isPureLauncherTransition(TransitionInfo info) { boolean isPureLauncherTransition = true; for (TransitionInfo.Change change : info.getChanges()) { if (!change.getLeash().toString().contains("com.android.launcher") || (change.getMode() != TRANSIT_OPEN && change.getMode() != TRANSIT_TO_BACK)) { isPureLauncherTransition = false; } } return isPureLauncherTransition; } public void hookRecentsMerge(TransitionInfo mergeInfo, SurfaceControl.Transaction t, RemoteAnimationTarget[] appearedTargets, IBinder mergedToken) { fixStartTOnRecentsMerge(mergeInfo, t, appearedTargets); adjustAppearedTargets(appearedTargets, mergeInfo, mergedToken); addFlagInRecentOnRemoteTargets(mergeInfo, appearedTargets); } private void fixStartTOnRecentsMerge(TransitionInfo mergeInfo, SurfaceControl.Transaction t, RemoteAnimationTarget[] appearedTargets) { if (mergeInfo == null) { return; } if (appearedTargets == null) { for (TransitionInfo.Change change : mergeInfo.getChanges()) { setAlphaForOpenActivityIfNeeded(mergeInfo, change, t); setPositionForFixRotation(mergeInfo, change, t); } } } private void adjustAppearedTargets(RemoteAnimationTarget[] appearedTargets, TransitionInfo info, IBinder mergedToken) { if (!ENABLE_INTERRUPT_TRANSITION) { return; } if (appearedTargets == null || info == null) { return; } boolean isBalAllow = OplusTransitionReflectionHelper.methodInvokeOnExt(info, GET_IS_BAL_ALLOW, null); boolean isRemoteFromLauncher = mTransitions.isRemoteOpenRequestedFrom(mergedToken, "QuickstepLaunch"); for (RemoteAnimationTarget appearedTarget : appearedTargets) { if (appearedTarget.mode == MODE_OPENING && appearedTarget.taskInfo.topActivityType == ACTIVITY_TYPE_STANDARD) { if (isBalAllow && !isRemoteFromLauncher) { OplusTransitionReflectionHelper.methodInvokeOnExt(appearedTarget, SET_IS_BAL_ALLOW, new Class<?>[]{boolean.class}, true); TransitionLog.debug("set remoteTarget: " + appearedTarget + " is balallow"); } else if (isRemoteFromLauncher) { OplusTransitionReflectionHelper.methodInvokeOnExt(appearedTarget, SET_IS_REMOTE_FROM_LAUNCHER, new Class<?>[]{boolean.class}, true); } } } } private void setAlphaForOpenActivityIfNeeded(TransitionInfo info, TransitionInfo.Change change, SurfaceControl.Transaction t) { int mode = change.getMode(); boolean openMode = (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT); if (openMode && TransitionUtil.isOpeningType(info.getType()) && (change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0 && change.getTaskInfo() == null) { TransitionLog.debug("set alpha 1 of activity:" + change); t.setAlpha(change.getLeash(), 1); } } private void setPositionForFixRotation(TransitionInfo mergeInfo, TransitionInfo.Change change, SurfaceControl.Transaction t) { if (change.getStartRotation() == change.getEndRotation()) { return; } Bundle b = OplusTransitionReflectionHelper.getWindowInfoBundleFromChange(change); if (b != null && b.getBoolean(KEY_HAS_FIX_ROTATION_LEASH, false)) { final SurfaceControl leash = change.getLeash(); if (!TransitionInfo.isIndependent(change, mergeInfo)) { return; } boolean hasParent = change.getParent() != null; final int rootIdx = TransitionUtil.rootIndexFor(change, mergeInfo); if (!hasParent) { t.setPosition(leash, change.getStartAbsBounds().left - mergeInfo.getRoot(rootIdx).getOffset().x, change.getStartAbsBounds().top - mergeInfo.getRoot(rootIdx).getOffset().y); TransitionLog.debug("set position for " + change + ", when has fix rotation"); } } } public void sendRecentsController(IBinder transition, RecentsTransitionHandler handler, TransitionInfo info) { if (!ENABLE_INTERRUPT_TRANSITION) { return; } if (handler != null) { RecentsTransitionHandler.RecentsController recentsController = handler.getRecentController(transition); if (recentsController != null) { setRecentsController(info, recentsController); TransitionLog.debug("sendRecentsController, info:" + info); } } } private static void setRecentsController(TransitionInfo info, RecentsTransitionHandler.RecentsController recentsController) { if (info == null || recentsController == null) { return; } try { Field ext = info.getClass().getDeclaredField(EXT); ext.setAccessible(true); Object infoExt = ext.get(info); if (infoExt != null) { Method getExtendedInfo = infoExt.getClass().getDeclaredMethod(GET_EXTENDED_INFO); getExtendedInfo.setAccessible(true); Object extendedInfo = getExtendedInfo.invoke(infoExt); if (extendedInfo != null) { Method setRecentsController = extendedInfo.getClass().getDeclaredMethod(SET_RECENTS_CONTROLLER, IRecentsAnimationController.class); setRecentsController.setAccessible(true); setRecentsController.invoke(extendedInfo, recentsController); } } } catch (Exception e) { Log.e(TAG, "setRecentsController error : " + e); } } public RemoteAnimationTarget initTargetWithTaskLeash(TransitionInfo.Change change, int layer, TransitionInfo mergeInfo, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap, TransitionInfo recentInfo) { // We are receiving new opening leaf tasks, so convert to onTasksAppeared. final RemoteAnimationTarget target = TransitionUtil.newTarget( change, layer, mergeInfo, t, leashMap); // reparent into the original `mInfo` since that's where we are animating. final int rootIdx = TransitionUtil.rootIndexFor(change, recentInfo); t.reparent(target.leash, recentInfo.getRoot(rootIdx).getLeash()); t.setLayer(target.leash, layer); // Hide the animation leash, let listener show it. t.hide(target.leash); return target; } //#ifdef OPLUS_FEATURE_INTERRUPT_TRANSITION //wenguangyu@Android.WMS, 2024/01/19, add for notify transitions state to WmCore public void notifyTransitionRemoveTask(IBinder playingToken, boolean isRecentsPlaying, IBinder mergedToken, TransitionInfo mergedInfo, int removeTaskId, WindowOrganizer organizer) { if (!ENABLE_INTERRUPT_TRANSITION) { return; } if (playingToken == null || mergedToken == null || mergedInfo == null || !isRecentsPlaying) { return; } /*if (OplusRemoteInterruptManager.ReflectionHelper.getIsFromHome(mergedInfo)) { notifyStartCompleted(mergedInfo, mergedAborted, organizer); } playing.mHandler.updateFinishT(playing.mToken, merged.mFinishT);*/ organizer.notifyTransitionRemoveTask(playingToken, mergedToken, removeTaskId); } public void notifyTransitionMerged(IBinder playing, IBinder merged, boolean isRecentsPlaying, WindowOrganizer organizer) { if (!ENABLE_INTERRUPT_TRANSITION || playing == null || merged == null || !isRecentsPlaying) { return; } organizer.notifyTransitionMerged(playing, merged); } /** * first start remote transition, then start recents transition and trigger interrupt scene * @param playing remote transition token * @param merged recents transition token * @param organizer WindowOrgnaizer object */ public void notifyRemoteInterrupt(IBinder playing, IBinder merged, WindowOrganizer organizer) { organizer.notifyRemoteInterrupt(playing, merged); } private void notifyStartCompleted(TransitionInfo info, boolean abort, WindowOrganizer organizer) { if (TransitionUtil.isOpeningType(info.getType())) { ActivityManager.RunningTaskInfo runningTaskInfo = null; for (int i = 0; i < info.getChanges().size(); i++) { TransitionInfo.Change change = info.getChanges().get(i); ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo != null) { if (runningTaskInfo != null) { break; } else if (TransitionUtil.isOpeningType(change.getMode()) && taskInfo.isVisibleRequested && taskInfo.topActivityType != ACTIVITY_TYPE_HOME) { runningTaskInfo = taskInfo; } } } if (runningTaskInfo != null) { organizer.notifyStartCompleted(runningTaskInfo.token, abort); } } } //#endif /*OPLUS_FEATURE_INTERRUPT_TRANSITION*/ //#ifdef OPLUS_FEATURE_SHELL_TRANSITION //Guochunlin@ANDROID.WMS 2024/02/08, Add to notify launcher private boolean isLandAppOpen(TransitionInfo info) { if (info != null) { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); int endFixedRotation = change.getEndFixedRotation(); if (info.getType() == TRANSIT_OPEN && (endFixedRotation == Surface.ROTATION_90 || endFixedRotation == Surface.ROTATION_270)) { TransitionLog.debug("isLandAppOpen: endFixedRotation = " + endFixedRotation); return true; } } } return false; } public boolean isLandScapeExitScene(IBinder token, Transitions.TransitionHandler handler, ShellTaskOrganizer organizer, RemoteTransitionHandler remoteTransitionHandler, TransitionInfo info, Context context) { if (handler == null || context == null) { return false; } boolean isRecentsAnimation = (handler instanceof RecentsTransitionHandler); /*if (!isRecentsAnimation && (handler instanceof RecentsMixedTransition)) { RecentsMixedTransition recentsMixedTransition = (RecentsMixedTransition) handler; isRecentsAnimation = recentsMixedTransition.isAnimateRecentsDuringSplit(); }*/ boolean isRemoteAnimation = false; boolean isChangeAnimationFromLandToPort = false; if (!isRecentsAnimation) { isRemoteAnimation = (info.getType() == TRANSIT_OPEN) && (mRemoteTransitionToken == token); isChangeAnimationFromLandToPort = (info.getType() == TRANSIT_CHANGE) && isChangeAnimationFromLandToPort(info); } if (isRecentsAnimation || isRemoteAnimation || isChangeAnimationFromLandToPort) { TransitionLog.always("isRecentsAnimation is: " + isRecentsAnimation + " isRemoteAnimation " + isRemoteAnimation); int currentRotation = context.getResources().getConfiguration() .windowConfiguration.getRotation(); boolean isLandScape = (currentRotation == Surface.ROTATION_90 || currentRotation == Surface.ROTATION_270) || isLandAppOpen(info); if (isChangeAnimationFromLandToPort && mIsLandScapeExitScene) { mIsLandScapeExitScene = false; TransitionLog.always("isLandScapeExitScene and mIsLandScapeExitScene is: " + mIsLandScapeExitScene + ", change animation from land to port, notify launcher to cancel listener"); organizer.onLandScapeSceneExit(true); return true; } if (isLandScape) { mIsLandScapeExitScene = true; TransitionLog.always("isLandScapeExitScene and mIsLandScapeExitScene is: " + mIsLandScapeExitScene); return true; } else if (isRecentsAnimation) { mIsLandScapeExitScene = false; TransitionLog.always("isLandScapeExitScene and mIsLandScapeExitScene is: " + mIsLandScapeExitScene + ", notify launcher to cancel listener"); organizer.onLandScapeSceneExit(false); return false; } } return false; } private boolean isChangeAnimationFromLandToPort(TransitionInfo info) { if (info != null && info.getType() == TRANSIT_CHANGE) { for (TransitionInfo.Change change : info.getChanges()) { if (change.getMode() == TRANSIT_CHANGE && change.hasFlags(FLAG_IS_DISPLAY)) { int startRotation = change.getStartRotation(); int endRotation = change.getEndRotation(); boolean fromLand = (startRotation == Surface.ROTATION_90 || startRotation == Surface.ROTATION_270); boolean toPort = (endRotation == Surface.ROTATION_0 || endRotation == Surface.ROTATION_180); return fromLand && toPort; } } } return false; } public boolean notifyLauncherStartActivity(TransitionInfo info, ShellTaskOrganizer organizer, IBinder transitionToken, RemoteTransitionHandler remoteTransitionHandler) { if (mIsLandScapeExitScene) { if (info.getType() == TRANSIT_CHANGE || isRotationChange(info)) { TransitionLog.always("Transition Change excuted by last landscape application and transition type is: " + info.getType()); mIsLandScapeExitScene = false; organizer.onLandScapeSceneExit(true); return true; } else { ArrayMap<IBinder, RemoteTransition> requestedRemotes = remoteTransitionHandler.getRequestedRemotes(); boolean isOpenRemote = (info.getType() == TRANSIT_OPEN) && (requestedRemotes != null) && (requestedRemotes.get(transitionToken) != null); if (isOpenRemote) { mIsLandScapeExitScene = false; TransitionLog.always("reset mIsLandScapeExitScene"); return true; } } } return false; } private boolean isRotationChange(TransitionInfo info) { if (info != null && info.getType() == TRANSIT_PIP) { for (TransitionInfo.Change change : info.getChanges()) { if (change.getMode() == TRANSIT_CHANGE && change.hasFlags(FLAG_IS_DISPLAY)) { int startRotation = change.getStartRotation(); int endRotation = change.getEndRotation(); TransitionLog.always("isRotationChange and startRotation: " + startRotation + " endRotation: " + endRotation); return startRotation != endRotation; } } } return false; } public void setRemoteTransitionToken(IBinder token) { mRemoteTransitionToken = token; } public boolean keyBackPressWithAvoidQuickBack(TransitionInfo info) { if (!ENABLE_INTERRUPT_TRANSITION) { return false; } return (boolean) OplusTransitionReflectionHelper.methodInvokeOnExt(info, GET_AVOID_INTERCEPT_KEY_EVENT_TO_HOME, null) || isBackToHome(info); } private boolean isBackToHome(TransitionInfo info) { if (null == info || null == info.getChanges()) { return false; } final int numChanges = info.getChanges().size(); boolean isHomeToFront = false; boolean isOpeningAppToClose = false; if (numChanges == 2 && info.getType() == WindowManager.TRANSIT_CLOSE) { for (int i = numChanges - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (null == change) { return false; } if (change.getMode() == WindowManager.TRANSIT_TO_FRONT && change.getTaskInfo() != null && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) { TransitionLog.debug("isHomeToFront"); isHomeToFront = true; } else if (change.getMode() == WindowManager.TRANSIT_CLOSE) { TransitionLog.debug("isOpeningAppToClose"); isOpeningAppToClose = true; } } } return isHomeToFront && isOpeningAppToClose; } //#endif /*OPLUS_FEATURE_SHELL_TRANSITION*/ public void updateMergeRemoteTaskVisible(TransitionInfo mergeInfo, SurfaceControl.Transaction finishT) { if (isRecentFinishToHome() && finishT != null && (mergeInfo.getType() == TRANSIT_OPEN // hewei add for ALM: 7130945 || mergeInfo.getType() == TRANSIT_TO_FRONT)) { TransitionLog.always("not apply merge finishT"); for (TransitionInfo.Change change : mergeInfo.getChanges()) { if (change.getEndDisplayId() >= OPLUS_MIRAGE_DISPLAY || change.getEndDisplayId() == OPLUS_MIRAGE_TVDISPLAY || change.getLeash() == null || !change.getLeash().isValid()) { continue; } if (TransitionUtil.isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE && (change.getFlags() & FLAG_MOVED_TO_TOP) != 0) { if ((change.getTaskInfo() != null && change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) || (change.getActivityComponent() != null)) { finishT.hide(change.getLeash()); } } if (TransitionUtil.isClosingType(change.getMode()) && change.getTaskInfo() != null && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) { finishT.show(change.getLeash()); } } } } public void applyStartTransactionOnAbortIfNeed(@NonNull Transitions.ActiveTransition playing, @NonNull Transitions.ActiveTransition ready) { if (!ENABLE_INTERRUPT_TRANSITION) { return; } if (playing.mHandler != null && !(playing.mHandler instanceof DefaultTransitionHandler) && ready.mStartT != null && ready.mInfo.getChanges().size() > 0) { // add for alm 8129143 if (ready.mInfo != null && ready.mInfo.getType() == TRANSIT_OPEN) { for (TransitionInfo.Change change : ready.mInfo.getChanges()) { if (change.hasAllFlags(FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT | FLAG_IS_BEHIND_STARTING_WINDOW) && change.getStartRotation() != change.getEndRotation()) { TransitionLog.always("Do not apply startT before merge"); return; } } } ready.mStartT.apply(); TransitionLog.always("apply startT of aborted " + ready + "; before merged into " + playing); } } //#ifdef OPLUS_FEATURE_INTERRUPT_TRANSITION //Guochunlin@ANDROID.WMS 2024/5/11, Add for bug 7265043 public boolean isToHomeAnimation(TransitionInfo mergeInfo, TransitionInfo recentsInfo) { if (!ENABLE_INTERRUPT_TRANSITION) { return false; } List<TransitionInfo.Change> changes = mergeInfo.getChanges(); Transitions.ActiveTransition activeTransition = mTransitions.getActiveTransition(recentsInfo.getTrack()); if (mergeInfo.getType() == TRANSIT_TO_BACK && changes.size() == 1 && activeTransition != null && activeTransition.mMerged != null) { TransitionInfo.Change change = changes.get(0); if (change.getTaskInfo() != null && change.getMode() == TRANSIT_TO_BACK) { return true; } } //Pusam.Huang@ANDROID.WMS 2024/09/23, Add for bug 7940700, begin. if (mergeInfo.getType() == TRANSIT_CLOSE && changes.size() == 1 && activeTransition != null) { TransitionInfo.Change change = changes.get(0); if (change.getTaskInfo() != null && change.getMode() == TRANSIT_CLOSE) { return true; } } //2024/09/23, Add for bug 7940700, end. boolean onlyHomeToFront = false; for (TransitionInfo.Change change : changes) { if (change.getTaskInfo() != null && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME && (TransitionUtil.isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE)) { onlyHomeToFront = true; } else if (TransitionUtil.isOpeningType(change.getMode())) { onlyHomeToFront = false; break; } } return onlyHomeToFront; } public void addFlagInRecentOnRemoteTargets(TransitionInfo info, RemoteAnimationTarget[] appearedTargets) { if (info == null || appearedTargets == null) { return; } for (int i = 0; i < appearedTargets.length; i++) { RemoteAnimationTarget appearedTarget = appearedTargets[i]; if (appearedTarget != null && appearedTarget.mode != MODE_CLOSING) { boolean taskNotInRecents = (boolean) OplusTransitionReflectionHelper.methodInvokeOnExt(info, GET_TASK_NOT_IN_RECENT_ON_EXTINFO, null); if (taskNotInRecents) { OplusTransitionReflectionHelper.methodInvokeOnExt(appearedTarget, SET_IS_TASK_NOT_IN_RECENTS, new Class<?>[]{boolean.class}, true); TransitionLog.always("Appeared opening task " + appearedTarget.taskId + " is not in recents, notify remote to close recents anim, notInRecent = " + OplusTransitionReflectionHelper.methodInvokeOnExt(appearedTarget, GET_IS_TASK_NOT_IN_RECENTS, null)); } int requestTransitionTaskId = (int) OplusTransitionReflectionHelper.methodInvokeOnExt(info, GET_REQUEST_TRANSITION_TASK_ID, null); if (requestTransitionTaskId != -1) { OplusTransitionReflectionHelper.methodInvokeOnExt(appearedTarget, SET_REQUEST_TRANSITION_TASK_ID, new Class<?>[]{int.class}, requestTransitionTaskId); TransitionLog.always("Appeared opening task " + appearedTarget.taskId + " set request transition task id " + OplusTransitionReflectionHelper.methodInvokeOnExt(appearedTarget, GET_REQUEST_TRANSITION_TASK_ID, null)); } } } } /* *construct a closing remoteAnimationTarget to notify launcher by onTasksAppeared */ public void constructCloseRemoteAnimationTarget(RemoteAnimationTarget[] appearedTargets, ArrayList<TransitionInfo.Change> closingTasks) { if (closingTasks != null && closingTasks.size() == 1) { final TransitionInfo.Change change = closingTasks.get(0); ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); appearedTargets[0] = new RemoteAnimationTarget(taskInfo.taskId /* taskId */, -1, null, false /* isTranslucent */, null /* clipRect */, null /* contentInsets */, -1 /* prefixOrderIndex */, null /* position */, null, null, taskInfo.configuration.windowConfiguration, false, null /* startLeash */, null /* startBounds */, taskInfo /* taskInfo */, false /* allowEnterPip */); OplusTransitionReflectionHelper.methodInvokeOnExt(appearedTargets[0], SET_MERGE_BACK_ANIMATION_TO_RECENTS, new Class<?>[]{boolean.class}, true); TransitionLog.debug("setMergeBackAnimationToRecents true"); } } //#endif /*OPLUS_FEATURE_INTERRUPT_TRANSITION*/ public void hideMergedToRecentsTask(TransitionInfo info, int taskId) { if (info == null || taskId <= 0) { return; } Transitions.ActiveTransition active = mTransitions.getActiveTransition(info.getTrack()); if (active != null && active.mHandler instanceof RecentsTransitionHandler && active.mMerged != null) { int size = active.mMerged.size(); for (int i = size - 1; i >= 0; i--) { final Transitions.ActiveTransition toMerge = active.mMerged.get(i); for (TransitionInfo.Change change : toMerge.mInfo.getChanges()) { if (change == null || change.getLeash() == null || !change.getLeash().isValid()) { continue; } int mode = change.getMode(); if (change.getTaskInfo() != null && change.getTaskInfo().taskId == taskId && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { toMerge.mFinishT.hide(change.getLeash()); TransitionLog.always("hide closing task: " + change.getLeash() + "in transition: " + toMerge.mInfo.getDebugId()); return; } } } } } public SurfaceControl adjustLeashAtRecentStart(TransitionInfo.Change change, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { SurfaceControl leash = change.getLeash(); t.setAlpha(change.getLeash(), 1); t.show(change.getLeash()); if (leashMap != null) { leashMap.put(change.getLeash(), leash); } return leash; } public int getBgColorForActivityTransition(TransitionInfo info, TransitionInfo.Change change, Animation a) { if (!ENABLE_INTERRUPT_TRANSITION) { return 0; } int bgColor = 0; final Context uiContext = ActivityThread.currentActivityThread() .getSystemUiContext(); bgColor = uiContext.getColor(com.android.internal.R.color.overview_background); bgColor = getTransitionBackgroundColorIfSet(info, change, a, bgColor); return bgColor; } public void addBackgroundColorOnTask(TransitionInfo info, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction) { if (!ENABLE_INTERRUPT_TRANSITION) { return; } boolean isOplusAnimRes = OplusTransitionReflectionHelper .methodInvokeOnExt(info, IS_OPLUS_ANIM_RES, null); boolean isSupportType = info.getType() == TRANSIT_OPEN || info.getType() == TRANSIT_CLOSE; final Color bgColor = Color.valueOf(Color.BLACK); final float[] colorArray = new float[]{bgColor.red(), bgColor.green(), bgColor.blue()}; final SurfaceControl parentSC = OplusTransitionReflectionHelper .methodInvokeOnExt(info, GET_PARENT_LEASH_FOR_BG_COLOR, null); if (parentSC == null || !isSupportType) { return; } for (int i = 0; i < info.getRootCount(); ++i) { final SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder() .setName("activity-level-anim-background") .setCallsite("DefaultTransitionHandler") .setColorLayer(); colorLayerBuilder.setParent(parentSC); TransitionLog.always("addBackgroundColorOnTask bgColor=" + bgColor + ", parentSC=" + parentSC + ", isOplusAnimRes=" + isOplusAnimRes + ", info=" + info + ", colorLayerBuilder=" + colorLayerBuilder); final SurfaceControl backgroundSurface = colorLayerBuilder.build(); startTransaction.setColor(backgroundSurface, colorArray) .setLayer(backgroundSurface, Integer.MIN_VALUE) .show(backgroundSurface); finishTransaction.remove(backgroundSurface); } } public boolean isRemoteReadyMergeToRecents(IBinder token, String debugName) { if (ENABLE_INTERRUPT_TRANSITION) { return mTransitions.isRemoteOpenRequestedFrom(token, debugName); } return false; } public boolean ifInvokeCallBackInInterrupt(boolean onlyHomeToFront, RemoteAnimationTarget[] appearedTargets, IBinder mergedToken, TransitionInfo info) { if (mergedToken == null || info == null) { return false; } boolean isRemoteFromSystemUi = mTransitions.isRemoteOpenRequestedFrom(mergedToken, "SysUILaunch"); boolean isRemoteFromLauncher = mTransitions.isRemoteOpenRequestedFrom(mergedToken, "QuickstepLaunch"); boolean isBalAllow = OplusTransitionReflectionHelper.methodInvokeOnExt(info, GET_IS_BAL_ALLOW, null); boolean isFromOverlay = OplusTransitionReflectionHelper.methodInvokeOnExt(info, GET_IS_FROM_OVERLAY, null); boolean isAssistScreenShowing = OplusTransitionReflectionHelper.methodInvokeOnExt(info, IS_ASSIST_SCREEN_SHOWING, null); boolean notRemoteT = !isRemoteFromLauncher && !isRemoteFromSystemUi; boolean specialScenes = !isBalAllow && !isFromOverlay && !isAssistScreenShowing; return !onlyHomeToFront && (appearedTargets == null || (notRemoteT && specialScenes)); } } 解析以上写好的类的方法与含义
07-18
评论 20
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值