Android 7.1 SystemUI近期任务打开应用流程

平台

RK3288 + Android 7.1

概述

从Launcher中启动应用和从Recent列表中启动应用是否是一致的?

有以下几种情况:

  1. 应用未启动过
  |-launcher启动:
	2017-01-01 21:12:56.490 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.calculator2/.Calculator bnds=[960,678][1235,834] (has extras)} from uid 10036 on display 0
	2017-01-01 21:12:56.512 system_process I/ActivityManager: Start proc 1719:com.android.calculator2/u0a32 for activity com.android.calculator2/.Calculator
	2017-01-01 21:12:57.070 system_process I/ActivityManager: Displayed com.android.calculator2/.Calculator: +569ms
  |-Recent启动:
	2017-01-01 21:15:11.067 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10300000 cmp=com.android.calculator2/.Calculator} from uid 10036 on display 0
	2017-01-01 21:15:11.108 system_process I/ActivityManager: Start proc 1394:com.android.calculator2/u0a32 for activity com.android.calculator2/.Calculator
	2017-01-01 21:15:11.578 system_process I/ActivityManager: Displayed com.android.calculator2/.Calculator: +492ms
  1. 应用已启动, 但使用HOME键切换到了后台
  |-Launcher
	2017-01-01 21:21:25.143 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.calculator2/.Calculator bnds=[960,678][1235,834] (has extras)} from uid 10036 on display 0
  |-Recent
	2017-01-01 21:22:17.313 system_process E/ActivityManager: applyOptionsLocked: Unknown animationType=0
  1. 应用已启动, 但已通过BACK键退出.
  |-Launcher
	2017-01-01 21:17:57.950 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.calculator2/.Calculator bnds=[960,678][1235,834] (has extras)} from uid 10036 on display 0
	2017-01-01 21:17:58.284 system_process I/ActivityManager: Displayed com.android.calculator2/.Calculator: +325ms
  |-Recent
	2017-01-01 21:18:57.879 system_process E/ActivityManager: applyOptionsLocked: Unknown animationType=0

LOG并不详尽, 仅供参考;
从上面中可以看出启动过程中除了第一种情况, 后面两种都存在差区别, 暂时没有深入研究的打算.

分析

先看layout布局, AndroidStudio > Tools > Layout Inspector
如图:
在这里插入图片描述

|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java

	@Override
     public void onClick(final View v) {
    
    
        if (mIsDisabledInSafeMode) {
    
    
            Context context = getContext();
            String msg = context.getString(R.string.recents_launch_disabled_message, mTask.title);
            if (mDisabledAppToast != null) {
    
    
                mDisabledAppToast.cancel();
            }
            mDisabledAppToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
            mDisabledAppToast.show();
            return;
        }

        boolean screenPinningRequested = false;
        if (v == mActionButtonView) {
    
    
            // Reset the translation of the action button before we animate it out
            mActionButtonView.setTranslationZ(0f);
            screenPinningRequested = true;
        }
        EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
                screenPinningRequested));

        MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
                mTask.key.getComponent().toString());
    }

//LaunchTaskEvent, 保存任务信息.
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java

public class LaunchTaskEvent extends EventBus.Event {
    
    

    public final TaskView taskView;
    public final Task task;
    public final Rect targetTaskBounds;
    public final int targetTaskStack;
    public final boolean screenPinningRequested;

    public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, int targetTaskStack,
            boolean screenPinningRequested) {
    
    
        this.taskView = taskView;
        this.task = task;
        this.targetTaskBounds = targetTaskBounds;
        this.targetTaskStack = targetTaskStack;
        this.screenPinningRequested = screenPinningRequested;
    }

}

|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java

public class EventBus extends BroadcastReceiver {
    
    

    private static final String TAG = "EventBus";
    private static final boolean DEBUG_TRACE_ALL = false;

	//...

    /**
     * An event super class that allows us to track internal event state across subscriber
     * invocations.
     *
     * Events should not be edited by subscribers.
     */
    public static class Event implements Cloneable {
    
    
        // Indicates that this event's dispatch should be traced and logged to logcat
        boolean trace;
        // Indicates that this event must be posted on the EventBus's looper thread before invocation
        boolean requiresPost;
        // Not currently exposed, allows a subscriber to cancel further dispatch of this event
        boolean cancelled;

        // Only accessible from derived events
        protected Event() {
    
    }

        /**
         * Called by the EventBus prior to dispatching this event to any subscriber of this event.
         */
        void onPreDispatch() {
    
    
            // Do nothing
        }

        /**
         * Called by the EventBus after dispatching this event to every subscriber of this event.
         */
        void onPostDispatch() {
    
    
            // Do nothing
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
    
    
            Event evt = (Event) super.clone();
            // When cloning an event, reset the cancelled-dispatch state
            evt.cancelled = false;
            return evt;
        }
    }

//--------------真正干活的:---------------------
	//...
//--------------------单例, 没什么特别的-------------
	/**
     * @return the default event bus for the application's main thread.
     */
    public static EventBus getDefault() {
    
    
        if (sDefaultBus == null)
        synchronized (sLock) {
    
    
            if (sDefaultBus == null) {
    
    
                if (DEBUG_TRACE_ALL) {
    
    
                    logWithPid("New EventBus");
                }
                sDefaultBus = new EventBus(Looper.getMainLooper());
            }
        }
        return sDefaultBus;
    }


    /**
     * Sends an event to the subscribers of the given event type immediately.  This can only be
     * called from the same thread as the EventBus's looper thread (for the default EventBus, this
     * is the main application thread).
     */
    public void send(Event event) {
    
    
        // Fail immediately if we are being called from the non-main thread
        long callingThreadId = Thread.currentThread().getId();
        if (callingThreadId != mHandler.getLooper().getThread().getId()) {
    
    
            throw new RuntimeException("Can not send() a message from a non-main thread.");
        }

        if (DEBUG_TRACE_ALL) {
    
    
            logWithPid("send(" + event.getClass().getSimpleName() + ")");
        }

        // Reset the event's cancelled state
        event.requiresPost = false;
        event.cancelled = false;
        queueEvent(event);
    }

    /**
     * Adds a new message.
     */
    private void queueEvent(final Event event) {
    
    
        ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass());
        if (eventHandlers == null) {
    
    
            return;
        }

        // Prepare this event
        boolean hasPostedEvent = false;
        event.onPreDispatch();

        // We need to clone the list in case a subscriber unregisters itself during traversal
        // TODO: Investigate whether we can skip the object creation here
        eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone();
        int eventHandlerCount = eventHandlers.size();
        for (int i = 0; i < eventHandlerCount; i++) {
    
    
            final EventHandler eventHandler = eventHandlers.get(i);
            if (eventHandler.subscriber.getReference() != null) {
    
    
                if (event.requiresPost) {
    
    
                    mHandler.post(new Runnable() {
    
    
                        @Override
                        public void run() {
    
    
                            processEvent(eventHandler, event);
                        }
                    });
                    hasPostedEvent = true;
                } else {
    
    
                    processEvent(eventHandler, event);
                }
            }
        }

        // Clean up after this event, deferring until all subscribers have been called
        if (hasPostedEvent) {
    
    
            mHandler.post(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    event.onPostDispatch();
                }
            });
        } else {
    
    
            event.onPostDispatch();
        }
    }

    /**
     * Processes and dispatches the given event to the given event handler, on the thread of whoever
     * calls this method.
     */
    private void processEvent(final EventHandler eventHandler, final Event event) {
    
    
        // Skip if the event was already cancelled
        if (event.cancelled) {
    
    
            if (event.trace || DEBUG_TRACE_ALL) {
    
    
                logWithPid("Event dispatch cancelled");
            }
            return;
        }

        try {
    
    
            if (event.trace || DEBUG_TRACE_ALL) {
    
    
                logWithPid(" -> " + eventHandler.toString());
            }
            Object sub = eventHandler.subscriber.getReference();
            if (sub != null) {
    
    
                long t1 = 0;
                if (DEBUG_TRACE_ALL) {
    
    
                    t1 = SystemClock.currentTimeMicro();
                }
                eventHandler.method.invoke(sub, event);
                if (DEBUG_TRACE_ALL) {
    
    
                    long duration = (SystemClock.currentTimeMicro() - t1);
                    mCallDurationMicros += duration;
                    mCallCount++;
                    logWithPid(eventHandler.method.toString() + " duration: " + duration +
                            " microseconds, avg: " + (mCallDurationMicros / mCallCount));
                }
            } else {
    
    
                Log.e(TAG, "Failed to deliver event to null subscriber");
            }
        } catch (IllegalAccessException e) {
    
    
            Log.e(TAG, "Failed to invoke method", e.getCause());
        } catch (InvocationTargetException e) {
    
    
            throw new RuntimeException(e.getCause());
        }
    }

eventHandler.method.invoke(sub, event);

首先, 从mEventTypeMap拿出eventHandlers:
ArrayList eventHandlers = mEventTypeMap.get(event.getClass());
再调用eventHandlers所有的元素传入processEvent.

mEventTypeMap
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java

    /**
     * Registers a new subscriber.
     */
    private void registerSubscriber(Object subscriber, int priority,
            MutableBoolean hasInterprocessEventsChangedOut) {
    
    
        // Fail immediately if we are being called from the non-main thread
        //...
        if (subscriberMethods != null) {
    
    
            if (DEBUG_TRACE_ALL) {
    
    
                logWithPid("Subscriber class type already registered");
            }

            // If we've parsed this subscriber type before, just add to the set for all the known
            // events
            for (EventHandlerMethod method : subscriberMethods) {
    
    
                ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(method.eventType);
                eventTypeHandlers.add(new EventHandler(sub, method, priority));
                sortEventHandlersByPriority(eventTypeHandlers);
            }
            mSubscribers.add(sub);
            return;
        } else {
    
    
            if (DEBUG_TRACE_ALL) {
    
    
                logWithPid("Subscriber class type requires registration");
            }

            // If we are parsing this type from scratch, ensure we add it to the subscriber type
            // map, and pull out he handler methods below
            subscriberMethods = new ArrayList<>();
            mSubscriberTypeMap.put(subscriberType, subscriberMethods);
            mSubscribers.add(sub);
        }
//...接着后面有一系列反射赋值, 很重要....
//主要是找出对应的这个函数名.
//private static final String METHOD_PREFIX = "onBusEvent";
	}

|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java

	@Override
    protected void onAttachedToWindow() {
    
    
        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
        EventBus.getDefault().register(mTouchHandler, RecentsActivity.EVENT_BUS_PRIORITY + 2);
        super.onAttachedToWindow();
    }

	
    public final void onBusEvent(LaunchTaskEvent event) {
    
    
		new Exception("ALog.onBusEvent").printStackTrace();
        mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
        mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
                event.taskView, event.screenPinningRequested, event.targetTaskBounds,
                event.targetTaskStack);
    }

|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java

    /**
     * Launches the specified {@link Task}.
     */
    public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
            final TaskStackView stackView, final TaskView taskView,
            final boolean screenPinningRequested, final Rect bounds, final int destinationStack) {
    
    
		new Exception("ALog.launchTaskFromRecents").printStackTrace();
        final ActivityOptions opts = ActivityOptions.makeBasic();
        if (bounds != null) {
    
    
            opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
        }

        final ActivityOptions.OnAnimationStartedListener animStartedListener;
        final IAppTransitionAnimationSpecsFuture transitionFuture;
        if (taskView != null) {
    
    
            transitionFuture = getAppTransitionFuture(new AnimationSpecComposer() {
    
    
                @Override
                public List<AppTransitionAnimationSpec> composeSpecs() {
    
    
                    return composeAnimationSpecs(task, stackView, destinationStack);
                }
            });
            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
    
    
                @Override
                public void onAnimationStarted() {
    
    
                    // If we are launching into another task, cancel the previous task's
                    // window transition
                    EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
                    EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
                    stackView.cancelAllTaskViewAnimations();

                    if (screenPinningRequested) {
    
    
                        // Request screen pinning after the animation runs
                        mStartScreenPinningRunnable.taskId = task.key.id;
                        mHandler.postDelayed(mStartScreenPinningRunnable, 350);
                    }
                }
            };
        } else {
    
    
            // This is only the case if the task is not on screen (scrolled offscreen for example)
            transitionFuture = null;
            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
    
    
                @Override
                public void onAnimationStarted() {
    
    
                    // If we are launching into another task, cancel the previous task's
                    // window transition
                    EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
                    EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
                    stackView.cancelAllTaskViewAnimations();
                }
            };
        }

        if (taskView == null) {
    
    
            // If there is no task view, then we do not need to worry about animating out occluding
            // task views, and we can launch immediately
            startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener);
        } else {
    
    
            LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
                    screenPinningRequested);
            if (task.group != null && !task.group.isFrontMostTask(task)) {
    
    
                launchStartedEvent.addPostAnimationCallback(new Runnable() {
    
    
                    @Override
                    public void run() {
    
    
                        startTaskActivity(stack, task, taskView, opts, transitionFuture,
                                animStartedListener);
                    }
                });
                EventBus.getDefault().send(launchStartedEvent);
            } else {
    
    
                EventBus.getDefault().send(launchStartedEvent);
                startTaskActivity(stack, task, taskView, opts, transitionFuture,
                        animStartedListener);
            }
        }
        Recents.getSystemServices().sendCloseSystemWindows(
                BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
    }
    /**
     * Starts the activity for the launch task.
     *
     * @param taskView this is the {@link TaskView} that we are launching from. This can be null if
     *                 we are toggling recents and the launch-to task is now offscreen.
     */
    private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
            ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture,
            final ActivityOptions.OnAnimationStartedListener animStartedListener) {
    
    
        SystemServicesProxy ssp = Recents.getSystemServices();
        if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts)) {
    
    
            // Keep track of the index of the task launch
            int taskIndexFromFront = 0;
            int taskIndex = stack.indexOfStackTask(task);
            if (taskIndex > -1) {
    
    
                taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
            }
            EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
        } else {
    
    
            // Dismiss the task if we fail to launch it
            if (taskView != null) {
    
    
                taskView.dismissTask();
            }

            // Keep track of failed launches
            EventBus.getDefault().send(new LaunchTaskFailedEvent());
        }

        if (transitionFuture != null) {
    
    
            ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture,
                    wrapStartedListener(animStartedListener), true /* scaleUp */);
        }
    }

|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java

	/** Starts an activity from recents. */
    public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
            ActivityOptions options) {
    
    
        if (mIam != null) {
    
    
            try {
    
    
                if (taskKey.stackId == DOCKED_STACK_ID) {
    
    
                    // We show non-visible docked tasks in Recents, but we always want to launch
                    // them in the fullscreen stack.
                    if (options == null) {
    
    
                        options = ActivityOptions.makeBasic();
                    }
                    options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
                }
                mIam.startActivityFromRecents(
                        taskKey.id, options == null ? null : options.toBundle());
                return true;
            } catch (Exception e) {
    
    
                Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
            }
        }
        return false;
    }

|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    @Override
    public final int startActivityFromRecents(int taskId, Bundle bOptions) {
    
    
        if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) {
    
    
            String msg = "Permission Denial: startActivityFromRecents called without " +
                    START_TASKS_FROM_RECENTS;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
        final long origId = Binder.clearCallingIdentity();
        try {
    
    
            synchronized (this) {
    
    
                return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions);
            }
        } finally {
    
    
            Binder.restoreCallingIdentity(origId);
        }
    }

剩下的就看ActivityManagerService的了…

猜你喜欢

转载自blog.csdn.net/ansondroider/article/details/98481682