• Android 11 替换Launcher后导致近期任务无效


    平台

         RK3566 + Android 11

    概述

        替换默认主界面, 更换为指定第三方Launcher后, 点击导航栏的RECENT键无效. 究其原因在于, 在旧版本SDK上, 删除Launcher3并不会影响RECENT的功能 , 而在新的SDK上, RECENT功能集成于Launcher3目录下, 删除 Launcher3后, 导致SystemUI调用对应的RECENT界面启动的服务失败.

    过程疏理

    frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java

        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            mNavigationBarView = (NavigationBarView) view;
            final Display display = view.getDisplay();
            // It may not have display when running unit test.
            if (display != null) {
                mDisplayId = display.getDisplayId();
                mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
            }
    
            mNavigationBarView.setComponents(mStatusBarLazy.get().getPanelController());
            mNavigationBarView.setDisabledFlags(mDisabledFlags1);
            mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
            mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
            if (savedInstanceState != null) {
                mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState);
            }
            mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
            mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
    
            prepareNavigationBarView();
        }
    
        private void prepareNavigationBarView() {
            mNavigationBarView.reorient();
    
            ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
            recentsButton.setOnClickListener(this::onRecentsClick);
            recentsButton.setOnTouchListener(this::onRecentsTouch);
            recentsButton.setLongClickable(true);
            recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
        }
    
        private void onRecentsClick(View v) {
            if (LatencyTracker.isEnabled(getContext())) {
                LatencyTracker.getInstance(getContext()).onActionStart(
                        LatencyTracker.ACTION_TOGGLE_RECENTS);
            }
            mStatusBarLazy.get().awakenDreams();
            mCommandQueue.toggleRecentApps();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java

       @Override
        public void toggleRecentApps() {
            // Ensure the device has been provisioned before allowing the user to interact with
            // recents
            if (!isUserSetup()) {
                return;
            }
    
            mImpl.toggleRecentApps();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java

       @Override
        public void toggleRecentApps() {
            Log.d(TAG, "toggleRecentApps");
            // If connected to launcher service, let it handle the toggle logic
            IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
            if (overviewProxy != null) {
                final Runnable toggleRecents = () -> {
                    try {
                        if (mOverviewProxyService.getProxy() != null) {
                            mOverviewProxyService.getProxy().onOverviewToggle();
                            mOverviewProxyService.notifyToggleRecentApps();
                        }
                    } catch (RemoteException e) {
                        Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
                    }
                };
                // Preload only if device for current user is unlocked
                if (mStatusBarLazy != null && mStatusBarLazy.get().isKeyguardShowing()) {
                    mStatusBarLazy.get().executeRunnableDismissingKeyguard(() -> {
                            // Flush trustmanager before checking device locked per user
                            mTrustManager.reportKeyguardShowingChanged();
                            mHandler.post(toggleRecents);
                        }, null,  true /* dismissShade */, false /* afterKeyguardGone */,
                        true /* deferred */);
                } else {
                    toggleRecents.run();
                }
                return;
            } else {
                // Do nothing
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    重点看下overviewProxy

    frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java

        private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
    
        @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
        @Inject
        public OverviewProxyService(Context context, CommandQueue commandQueue,
                NavigationBarController navBarController, NavigationModeController navModeController,
                NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
                PipUI pipUI, Optional<Divider> dividerOptional,
                Optional<Lazy<StatusBar>> statusBarOptionalLazy,
                BroadcastDispatcher broadcastDispatcher) {
            super(broadcastDispatcher);
            mContext = context;
            mPipUI = pipUI;
            mStatusBarOptionalLazy = statusBarOptionalLazy;
            mHandler = new Handler();
            mNavBarController = navBarController;
            mStatusBarWinController = statusBarWinController;
            mConnectionBackoffAttempts = 0;
            mDividerOptional = dividerOptional;
    //frameworks/base/core/res/res/values/config.xml
    //    com.android.launcher3/com.android.quickstep.RecentsActivity
            mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
                    com.android.internal.R.string.config_recentsComponentName));
            mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
        }
    
        //绑定服务
        private void internalConnectToCurrentUser() {
            //..............
            Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
                    .setPackage(mRecentsComponentName.getPackageName());
            try {
                mBound = mContext.bindServiceAsUser(launcherServiceIntent,
                        mOverviewServiceConnection,
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                        UserHandle.of(getCurrentUserId()));
            } catch (SecurityException e) {
                Log.e(TAG_OPS, "Unable to bind because of security error", e);
            }
            //.....
        }
        //绑定成功
            private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //.........
                mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
            }
    
        //由上面OverviewProxyRecentsImpl 调用
        public IOverviewProxy getProxy() {
            return mOverviewProxy;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    近期任务UI的实现有别与旧版本的SDK, 有frameworks/base/packages/SystemUI改到了packages/apps/Launcher3/quickstep

    packages/apps/Launcher3/quickstep/AndroidManifest.xml

                <service
                android:name="com.android.quickstep.TouchInteractionService"
                android:permission="android.permission.STATUS_BAR_SERVICE"
                android:directBootAware="true" >
                <intent-filter>
                    <action android:name="android.intent.action.QUICKSTEP_SERVICE" />
                intent-filter>
            service>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    为了使用默认第三方Launcher, 需要注释掉quickstep自带的Launcher

    packages/apps/Launcher3/quickstep/AndroidManifest-launcher.xml

            <activity
                android:name="com.android.launcher3.uioverrides.QuickstepLauncher"
                android:launchMode="singleTask"
                android:clearTaskOnLaunch="true"
                android:stateNotNeeded="true"
                android:windowSoftInputMode="adjustPan"
                android:screenOrientation="unspecified"
                android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
                android:resizeableActivity="true"
                android:resumeWhilePausing="true"
                android:taskAffinity=""
                android:enabled="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <!--category android:name="android.intent.category.HOME" /-->
                    <category android:name="android.intent.category.DEFAULT" />
                    <!--category android:name="android.intent.category.MONKEY"/-->
                    <category android:name="android.intent.category.LAUNCHER_APP" />
                </intent-filter>
                <meta-data
                    android:name="com.android.launcher3.grid.control"
                    android:value="${packageName}.grid_control" />
            </activity>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    开机奔溃

        2022-07-10 04:01:50.179 1472-1472/com.android.launcher3 E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.android.launcher3, PID: 1472
        java.lang.RuntimeException: Unable to create service com.android.quickstep.TouchInteractionService: java.lang.NullPointerException: Attempt to read from field 'android.content.pm.ActivityInfo android.content.pm.ResolveInfo.activityInfo' on a null object reference
            at android.app.ActivityThread.handleCreateService(ActivityThread.java:4198)
            at android.app.ActivityThread.access$1500(ActivityThread.java:237)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loop(Looper.java:223)
            at android.app.ActivityThread.main(ActivityThread.java:7664)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
         Caused by: java.lang.NullPointerException: Attempt to read from field 'android.content.pm.ActivityInfo android.content.pm.ResolveInfo.activityInfo' on a null object reference
            at com.android.quickstep.OverviewComponentObserver.(OverviewComponentObserver.java:82)
            at com.android.quickstep.TouchInteractionService.onUserUnlocked(TouchInteractionService.java:345)
            at com.android.quickstep.-$$Lambda$6M6xH0rMyGjroOocJ2F5KYabvuw.run(Unknown Source:2)
            at com.android.quickstep.RecentsAnimationDeviceState.runOnUserUnlocked(RecentsAnimationDeviceState.java:272)
            at com.android.quickstep.TouchInteractionService.onCreate(TouchInteractionService.java:301)
            at android.app.ActivityThread.handleCreateService(ActivityThread.java:4186)
            at android.app.ActivityThread.access$1500(ActivityThread.java:237) 
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932) 
            at android.os.Handler.dispatchMessage(Handler.java:106) 
            at android.os.Looper.loop(Looper.java:223) 
            at android.app.ActivityThread.main(ActivityThread.java:7664) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java

        public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) {
            mContext = context;
            mDeviceState = deviceState;
            mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN)
                    .addCategory(Intent.CATEGORY_HOME)
                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            //异常位置: 由于前面注释掉了自带Launcher导致, 将mContext.getPackageName 替换成 三方Launcher的包名可解决.
            mMyHomeIntent = new Intent(mCurrentHomeIntent).setPackage(/*mContext.getPackageName()*/"com.android.launcherX");
            ResolveInfo info = context.getPackageManager().resolveActivity(mMyHomeIntent, 0);
            ComponentName myHomeComponent =
                    new ComponentName(/*mContext.getPackageName()*/"com.android.launcherX", info.activityInfo.name);
            mMyHomeIntent.setComponent(myHomeComponent);
            mConfigChangesMap.append(myHomeComponent.hashCode(), info.activityInfo.configChanges);
            ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class);
            mFallbackIntent = new Intent(Intent.ACTION_MAIN)
                    .addCategory(Intent.CATEGORY_DEFAULT)
                    .setComponent(fallbackComponent)
                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    
            try {
                ActivityInfo fallbackInfo = context.getPackageManager().getActivityInfo(
                        mFallbackIntent.getComponent(), 0 /* flags */);
                mConfigChangesMap.append(fallbackComponent.hashCode(), fallbackInfo.configChanges);
            } catch (PackageManager.NameNotFoundException ignored) { /* Impossible */ }
    
            mContext.registerReceiver(mUserPreferenceChangeReceiver,
                    new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED));
            updateOverviewTargets();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    解决奔溃问题后, 点击recent键返回了HOME, 而不是显示RECENT界面:

    packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java

    
        /**
         * Update overview intent and {@link BaseActivityInterface} based off the current launcher home
         * component.
         */
        private void updateOverviewTargets() {
            ComponentName defaultHome = PackageManagerWrapper.getInstance()
                    .getHomeActivities(new ArrayList<>());
    
            mIsHomeDisabled = mDeviceState.isHomeDisabled();
            mIsDefaultHome = Objects.equals(mMyHomeIntent.getComponent(), defaultHome);
    
            // Set assistant visibility to 0 from launcher's perspective, ensures any elements that
            // launcher made invisible become visible again before the new activity control helper
            // becomes active.
            if (mActivityInterface != null) {
                mActivityInterface.onAssistantVisibilityChanged(0.f);
            }
    
            if (SEPARATE_RECENTS_ACTIVITY.get()) {
                mIsDefaultHome = false;
                if (defaultHome == null) {
                    defaultHome = mMyHomeIntent.getComponent();
                }
            }
    
            //不走if分支, 
            if (false && !mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) {
                // User default home is same as out home app. Use Overview integrated in Launcher.
                mActivityInterface = LauncherActivityInterface.INSTANCE;
                mIsHomeAndOverviewSame = true;
                mOverviewIntent = mMyHomeIntent;
                mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent());
    
                // Remove any update listener as we don't care about other packages.
                unregisterOtherHomeAppUpdateReceiver();
            } else {
                // The default home app is a different launcher. Use the fallback Overview instead.
    
                mActivityInterface = FallbackActivityInterface.INSTANCE;
                mIsHomeAndOverviewSame = false;
                mOverviewIntent = mFallbackIntent;
                mCurrentHomeIntent.setComponent(defaultHome);
    
                // User's default home app can change as a result of package updates of this app (such
                // as uninstalling the app or removing the "Launcher" feature in an update).
                // Listen for package updates of this app (and remove any previously attached
                // package listener).
                if (defaultHome == null) {
                    unregisterOtherHomeAppUpdateReceiver();
                } else if (!defaultHome.getPackageName().equals(mUpdateRegisteredPackage)) {
                    unregisterOtherHomeAppUpdateReceiver();
    
                    mUpdateRegisteredPackage = defaultHome.getPackageName();
                    mContext.registerReceiver(mOtherHomeAppUpdateReceiver, getPackageFilter(
                            mUpdateRegisteredPackage, ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED,
                            ACTION_PACKAGE_REMOVED));
                }
            }
            mOverviewChangeListener.accept(mIsHomeAndOverviewSame);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    关键在于使mOverviewIntent = mFallbackIntent;

    由SystemUI调用onOverviewToggle:

    packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java

            @BinderThread
            @Override
            public void onOverviewToggle() {
                TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
                mOverviewCommandHelper.onOverviewToggle();
            }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java

        @BinderThread
        public void onOverviewToggle() {
            // If currently screen pinning, do not enter overview
            if (mDeviceState.isScreenPinningActive()) {
                return;
            }
    
            ActivityManagerWrapper.getInstance()
                    .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
            MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    MAIN_EXECUTOR 和 LooperExecutor

    AbstractExecutorService
    LooperExecutor
    Executors
    LooperExecutor MAIN_EXECUTOR

    RecentsActivityCommand

        private class RecentsActivityCommand<T extends StatefulActivity<?>> implements Runnable {
            protected final BaseActivityInterface<?, T> mActivityInterface;
            //.....
            private ActivityInitListener mListener;
    
            public RecentsActivityCommand() {
                mActivityInterface = mOverviewComponentObserver.getActivityInterface();
    			//....
            }
            @Override
            public void run() {
    			//...
                // Otherwise, start overview.
                mListener = mActivityInterface.createActivityInitListener(this::onActivityReady);
                mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
                        new RemoteAnimationProvider() {
                            @Override
                            public AnimatorSet createWindowAnimation(
                                    RemoteAnimationTargetCompat[] appTargets,
                                    RemoteAnimationTargetCompat[] wallpaperTargets) {
                                return RecentsActivityCommand.this.createWindowAnimation(appTargets,
                                        wallpaperTargets);
                            }
                        }, mContext, MAIN_EXECUTOR.getHandler(),
                        mAnimationProvider.getRecentsLaunchDuration());
            } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java

        /**
         * Get the current activity control helper for managing interactions to the overview activity.
         *
         * @return the current activity control helper
         */
        public BaseActivityInterface getActivityInterface() {
            return mActivityInterface;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    OverviewComponentObserver.mActivityInterface = FallbackActivityInterface.INSTANCE;

    packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java

    public final class FallbackActivityInterface extends
            BaseActivityInterface<RecentsState, RecentsActivity> {
    
        public static final FallbackActivityInterface INSTANCE = new FallbackActivityInterface();
    
        @Override
        public ActivityInitListener createActivityInitListener(
                Predicate<Boolean> onInitListener) {
            return new ActivityInitListener<>((activity, alreadyOnHome) ->
                    onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    packages/apps/Launcher3/quickstep/src/com/android/quickstep/util/ActivityInitListener.java

        /**
         * Starts the given intent with the provided animation. Unlike {@link #register(Intent)}, this
         * method will not call {@link #init} if the activity already exists, it will only call it when
         * we get handleIntent() for the provided intent that we're starting.
         */
        public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
                Context context, Handler handler, long duration) {
            mIsRegistered = true;
    
            Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle();
            context.startActivity(addToIntent(new Intent(intent)), options);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    最终context.startActivity 其中的Intent是:mOverviewComponentObserver.getOverviewIntent()

    packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java

        /**
         * Get the current intent for going to the overview activity.
         *
         * @return the overview intent
         */
        public Intent getOverviewIntent() {
        	/*参见前面的代码:
        	ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class);
            mFallbackIntent = new Intent(Intent.ACTION_MAIN)
                    .addCategory(Intent.CATEGORY_DEFAULT)
                    .setComponent(fallbackComponent)
                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             */
            return mOverviewIntent;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. getActivityInterface
    2.createActivityInitListener
    3.getOverviewIntent
    4.registerAndStartActivity
    RecentsActivityCommand
    OverviewComponentObserver
    FallbackActivityInterface
    ActivityInitListener
    void registerAndStartActivity()

    至此RecentsActivity启动完成.

    模块编译:

    mmm packages/apps/Launcher3/:Launcher3QuickStep -j4
    
    • 1

    需要注意的是

    1. 原生的Launcher3需要注释掉, 或让它不参与编译.
    2. 近期任务UI的存放目录是在Lauuncher3目录下, 而需要参与编译的模块只有Launcher3QuickStep
    3. 第三方Launcher不能使用com.android.launcher3这个包名, 与上面的模块冲突

    参考

    SystemUI之QuickStep探索(常规启动篇)
    Android11 最近任务Recents功能分析

  • 相关阅读:
    openGauss学习笔记-79 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT应用场景
    Vue项目搭建图文详解教程
    【Socket】两种高效事件处理模式&并发模式
    子2023
    数据结构上机实验——栈和队列的实现、栈和队列的应用、进制转换、约瑟夫环问题
    MYSQL练习题:每篇文章同时刻最大在看人数
    iOS APP 转让避坑指南
    高通导航器软件开发包使用指南(7)
    如何在服务器上搭建MQTT服务器
    2021年暨南大学计算机848真题
  • 原文地址:https://blog.csdn.net/ansondroider/article/details/126342245