android13#launcher3#recent#screenshot

441 阅读9分钟

1.简介

  • 主要学习下overview页面底部的两个功能按钮
  • 点击screenshot按钮以后的流程,然后快照弹框有2个按钮,可以编辑,分享快照,顺道学习下编辑按钮的逻辑 image.png

1.1.参考

参考上篇

>1.overview_actions_container.xml

        <com.android.quickstep.views.OverviewActionsView 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|bottom">

            <LinearLayout
                android:id="@+id/action_buttons"
                android:layout_width="match_parent"
                android:layout_height="@dimen/overview_actions_height"
                android:layout_gravity="bottom|center_horizontal"
                android:orientation="horizontal">

                <Space
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:layout_weight="1" />

                <Button
                    android:id="@+id/action_screenshot"
                    style="@style/OverviewActionButton"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:drawableStart="@drawable/ic_screenshot"
                    android:text="@string/action_screenshot"
                    android:theme="@style/ThemeControlHighlightWorkspaceColor" />

                <Space
                    android:id="@+id/action_split_space"
                    android:layout_width="@dimen/overview_actions_button_spacing"
                    android:layout_height="1dp"
                    android:visibility="gone" />

                <Button
                    android:id="@+id/action_split"
                    style="@style/OverviewActionButton"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/action_split"
                    android:theme="@style/ThemeControlHighlightWorkspaceColor"
                    android:visibility="gone" />

                <Space
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:layout_weight="1" />
    <!--三键导航可见,右侧比重是2,手势导航不可见,右侧比重是1-->
                <Space
                    android:id="@+id/oav_three_button_space"
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:layout_weight="1"
                    android:visibility="gone" />
            </LinearLayout>

        </com.android.quickstep.views.OverviewActionsView>

1.2.问题

  • 我们快照点击edit会跳转到如下页面,谷歌的photos应用
cmp=com.google.android.apps.photos/.editor.intents.EditActivity

>1.问题1

  • 在recent列表页面看到的是个黑屏,这个好像是photos自己的问题吧?
  • 更新了下photos应用,不再黑屏了

>2.问题2

  • recent列表点击这个编辑页面,没反应,无法打开,日志如下,搜索日志可以查到方法4.1
  • 解决办法就是4.2.1,在启动recent任务的时候,暂时无视intentFilter
  • 在4.1的开头会判断是否需要强制验证过滤器
Intent does not match component's intent filter: Intent { act=android.intent.action.EDIT dat=content://media/... typ=image/png flg=0x10108003 cmp=com.google.android.apps.photos/.editor.intents.EditActivity }
W  Access blocked: ComponentInfo{com.google.android.apps.photos/com.google.android.apps.photos.editor.intents.EditActivity}
I  START u0 {act=android.intent.action.EDIT dat=content://media/... typ=image/png flg=0x10108003 cmp=com.google.android.apps.photos/.editor.intents.EditActivity} from uid 10157
D  notifyAppTargetEvent action=1 launchLocation=task-switcher

2.OverviewActionsView

public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
        implements OnClickListener, Insettable {

2.1.参数

    private static final int INDEX_CONTENT_ALPHA = 0;
    private static final int INDEX_VISIBILITY_ALPHA = 1;
    private static final int INDEX_FULLSCREEN_ALPHA = 2;
    private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
    private static final int INDEX_SHARE_TARGET_ALPHA = 4;
    private static final int INDEX_SCROLL_ALPHA = 5;
    private static final int NUM_ALPHAS = 6;

2.2.onFinishInflate

    protected void onFinishInflate() {
        super.onFinishInflate();
        //线性布局容器的透明度控制
        mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS);
        mMultiValueAlpha.setUpdateVisibility(true);
//2个按钮的点击事件见补充1
        findViewById(R.id.action_screenshot).setOnClickListener(this);
        mSplitButton = findViewById(R.id.action_split);
        mSplitButton.setOnClickListener(this);
    }

>1.onClick

快照以及分屏两个按钮的点击事件如下,最终也是交给外部传递来的callback处理的

    public void onClick(View view) {
        if (mCallbacks == null) {
            return;
        }
        int id = view.getId();
        if (id == R.id.action_screenshot) {
            mCallbacks.onScreenshot();
        } else if (id == R.id.action_split) {
            mCallbacks.onSplit();
        }
    }

2.3.updateHiddenFlags

    public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
        if (enable) {
            mHiddenFlags |= visibilityFlags;
        } else {
            mHiddenFlags &= ~visibilityFlags;
        }
        boolean isHidden = mHiddenFlags != 0;
        mMultiValueAlpha.get(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
    }

2.4.updateDisabledFlags

    public void updateDisabledFlags(@ActionsDisabledFlags int disabledFlags, boolean enable) {
        if (enable) {
            mDisabledFlags |= disabledFlags;
        } else {
            mDisabledFlags &= ~disabledFlags;
        }
        boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
        LayoutUtils.setViewEnabled(this, isEnabled);
        updateSplitButtonEnabledState();
    }

>1.updateSplitButtonEnabledState

更新分屏按钮是否可见

    private void updateSplitButtonEnabledState() {
        if (mSplitButton == null) {
            return;
        }
        boolean isParentEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
        boolean shouldBeEnabled = mSplitButtonDisabledFlags == 0 && isParentEnabled;
        mSplitButton.setEnabled(shouldBeEnabled);
    }

callback来源

>2.TaskThumbnailView.java

    private void refreshOverlay() {
        if (mOverlayEnabled) {
        //见3.4.1
            getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.getMatrix(),
                    mPreviewPositionHelper.isOrientationChanged());
        } else {
            getTaskOverlay().reset();
        }
    }

3.4.TaskOverlayFactory.java

>1.initOverlay

    public static class TaskOverlay<T extends OverviewActionsView> {
    //..
        public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix,
                boolean rotated) {
            getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null);

            if (thumbnail != null) {
                getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
                boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot();
                //这个就是补充1用到的callback
                getActionsView().setCallbacks(new OverlayUICallbacksImpl(isAllowedByPolicy, task));
            }
        }

>2.OverlayUICallbacksImpl

        protected class OverlayUICallbacksImpl implements OverlayUICallbacks {
            protected final boolean mIsAllowedByPolicy;
            protected final Task mTask;

            public OverlayUICallbacksImpl(boolean isAllowedByPolicy, Task task) {
                mIsAllowedByPolicy = isAllowedByPolicy;
                mTask = task;
            }

            public void onScreenshot() {
                endLiveTileMode(() -> saveScreenshot(mTask));//回调见补充3
            }

            public void onSplit() {
                endLiveTileMode(TaskOverlay.this::enterSplitSelect);
            }
        }

>3.endLiveTileMode

        public void endLiveTileMode(@NonNull Runnable callback) {
            RecentsView recentsView = mThumbnailView.getTaskView().getRecentsView();
            //就是动画结束执行callback
            recentsView.switchToScreenshot(
                    () -> recentsView.finishRecentsAnimation(true /* toRecents */,
                            false /* shouldPip */, callback));
        }

        protected void saveScreenshot(Task task) {
            if (mThumbnailView.isRealSnapshot()) {
            //核心是这个,补充4
                mImageApi.saveScreenshot(mThumbnailView.getThumbnail(),
                        getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key);
            } else {
                showBlockedByPolicyMessage();
            }
        }

>4.saveScreenshot

ImageActionsApi.java

    public void saveScreenshot(Bitmap screenshot, Rect screenshotBounds,
            Insets visibleInsets, Task.TaskKey task) {
            //补充5
        ImageActionUtils.saveScreenshot(mSystemUiProxy, screenshot, screenshotBounds, visibleInsets,
                task);
    }

>5.saveScreenshot

ImageActionUtils

    public static void saveScreenshot(SystemUiProxy systemUiProxy, Bitmap screenshot,
            Rect screenshotBounds,
            Insets visibleInsets, Task.TaskKey task) {
            //最终见3.5
        systemUiProxy.handleImageBundleAsScreenshot(
                ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(screenshot),
                screenshotBounds, visibleInsets, task);
    }

3.5.OverviewProxyService.java

>1.handleImageBundleAsScreenshot

        public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
                Insets visibleInsets, Task.TaskKey task) {
                //3.6.1
            mScreenshotHelper.provideScreenshot(
                    screenImageBundle,
                    locationInScreen,
                    visibleInsets,
                    task.id,
                    task.userId,
                    task.sourceComponent,
                    SCREENSHOT_OVERVIEW,
                    mHandler,
                    null);
        }

3.6.ScreenshotHelper.java

>1.provideScreenshot

    public void provideScreenshot(@NonNull Bundle screenshotBundle, @NonNull Rect boundsInScreen,
            @NonNull Insets insets, int taskId, int userId, ComponentName topComponent,
            @ScreenshotSource int source, @NonNull Handler handler,
            @Nullable Consumer<Uri> completionConsumer) {
        ScreenshotRequest screenshotRequest = new ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE,
                source, screenshotBundle, boundsInScreen, insets, taskId, userId, topComponent);
        takeScreenshot(handler, screenshotRequest, SCREENSHOT_TIMEOUT_MS, completionConsumer);
    }

    private void takeScreenshot(@NonNull Handler handler,
            ScreenshotRequest screenshotRequest, long timeoutMs,
            @Nullable Consumer<Uri> completionConsumer) {
        synchronized (mScreenshotLock) {

            final Runnable mScreenshotTimeout = () -> {
                synchronized (mScreenshotLock) {
                    if (mScreenshotConnection != null) {
                        //超时
                        resetConnection();
                        notifyScreenshotError();
                    }
                }
                if (completionConsumer != null) {
                    completionConsumer.accept(null);
                }
            };

            Message msg = Message.obtain(null, 0, screenshotRequest);

            Handler h = new Handler(handler.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case SCREENSHOT_MSG_URI:
                            if (completionConsumer != null) {
                                completionConsumer.accept((Uri) msg.obj);
                            }
                            handler.removeCallbacks(mScreenshotTimeout);
                            break;
                        case SCREENSHOT_MSG_PROCESS_COMPLETE:
                            synchronized (mScreenshotLock) {
                                resetConnection();
                            }
                            break;
                    }
                }
            };
            msg.replyTo = new Messenger(h);

            if (mScreenshotConnection == null || mScreenshotService == null) {
                if (mScreenshotConnection != null) {
                    resetConnection();
                }
                //本地配置的快照服务组件
                final ComponentName serviceComponent = ComponentName.unflattenFromString(
                        mContext.getResources().getString(
                                com.android.internal.R.string.config_screenshotServiceComponent));
                final Intent serviceIntent = new Intent();

                serviceIntent.setComponent(serviceComponent);
                ServiceConnection conn = new ServiceConnection() {
                    @Override
                    public void onServiceConnected(ComponentName name, IBinder service) {
                        synchronized (mScreenshotLock) {
                            if (mScreenshotConnection != this) {
                                return;
                            }
                            mScreenshotService = service;
                            Messenger messenger = new Messenger(mScreenshotService);
                            try {
                            //参考补充2,就相当于mScreenshotService来处理msg
                                messenger.send(msg);
                            } catch (RemoteException e) {
                                if (completionConsumer != null) {
                                    completionConsumer.accept(null);
                                }
                            }
                        }
                    }

                    @Override
                    public void onServiceDisconnected(ComponentName name) {
                        synchronized (mScreenshotLock) {
                            if (mScreenshotConnection != null) {
                                resetConnection();
                                if (handler.hasCallbacks(mScreenshotTimeout)) {
                                    handler.removeCallbacks(mScreenshotTimeout);
                                    notifyScreenshotError();
                                }
                            }
                        }
                    }
                };//绑定服务组件
                if (mContext.bindServiceAsUser(serviceIntent, conn,
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                        UserHandle.CURRENT)) {
                    mScreenshotConnection = conn;
                    handler.postDelayed(mScreenshotTimeout, timeoutMs);
                }
            } else {
                Messenger messenger = new Messenger(mScreenshotService);

                try {
                    messenger.send(msg);
                } catch (RemoteException e) {
                    if (completionConsumer != null) {
                        completionConsumer.accept(null);
                    }
                }
                handler.postDelayed(mScreenshotTimeout, timeoutMs);
            }
        }
    }

>2.Messenger

    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

3.7.TakeScreenshotService.java

>1.onBind

    public IBinder onBind(Intent intent) {
        registerReceiver(mCloseSystemDialogs, new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS),
                Context.RECEIVER_EXPORTED);
        //对外就是交给这个mHandler处理的
        final Messenger m = new Messenger(mHandler);
        return m.getBinder();
    }

构造方法里初始化的

        mHandler = new Handler(Looper.getMainLooper(), this::handleMessage);

>2.handleMessage

msg就是3.6.1里传递过来的

    private boolean handleMessage(Message msg) {
        final Messenger replyTo = msg.replyTo;
        final Consumer<Uri> onSaved = (uri) -> reportUri(replyTo, uri);
        RequestCallback callback = new RequestCallbackImpl(replyTo);

        ScreenshotHelper.ScreenshotRequest request =
                (ScreenshotHelper.ScreenshotRequest) msg.obj;

        handleRequest(request, onSaved, callback);//里边会调用补充3
        return true;
    }

>3.dispatchToController

    private void dispatchToController(ScreenshotHelper.ScreenshotRequest request,
            Consumer<Uri> uriConsumer, RequestCallback callback) {
        ComponentName topComponent = request.getTopComponent();
        switch (request.getType()) {
            case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
                mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, callback);
                break;
            case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE://看这个

                Bitmap screenshot = ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap(
                        request.getBitmapBundle());
                Rect screenBounds = request.getBoundsInScreen();
                Insets insets = request.getInsets();
                int taskId = request.getTaskId();
                int userId = request.getUserId();

                if (screenshot == null) {
                //快照为空,弹个通知提示
                    mNotificationsController.notifyScreenshotError(
                            R.string.screenshot_failed_to_capture_text);
                    callback.reportError();
                } else {//最终走到3.8.2
                    mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
                            taskId, userId, topComponent, uriConsumer, callback);
                }
                break;
            default:
        }
    }

3.8.ScreenshotController.java

>1.构造方法

        mWindowLayoutParams = FloatingWindowUtil.getFloatingWindowParams();
        mWindow = FloatingWindowUtil.getFloatingWindow(mContext);
        mWindow.setWindowManager(mWindowManager, null, null);

        reloadAssets();//补充4

>2.saveScreenshot

    private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
            Insets screenInsets, ComponentName topComponent, boolean showFlash, UserHandle owner) {
//..
        mPackageName = topComponent == null ? "" : topComponent.getPackageName();
        mScreenshotView.setPackageName(mPackageName);

        mScreenshotView.updateOrientation(
                mWindowManager.getCurrentWindowMetrics().getWindowInsets());

        mScreenBitmap = screenshot;
//..这个会异步执行3.10任务
        saveScreenshotInWorkerThread(owner, finisher, this::showUiOnActionsReady,
                this::showUiOnQuickShareActionReady);
//.
        attachWindow();//补充3

        mScreenshotView.setScreenshot(mScreenBitmap, screenInsets);

        setContentView(mScreenshotView);
        //..
        mScreenshotHandler.cancelTimeout(); // restarted after animation
    }

>3.attachWindow

    private void attachWindow() {
        View decorView = mWindow.getDecorView();
        if (decorView.isAttachedToWindow() || mBlockAttach) {
            return;
        }
        mBlockAttach = true;
        mWindowManager.addView(decorView, mWindowLayoutParams);
        decorView.requestApplyInsets();
    }

>4.reloadAssets

  • 加载一个布局,添加到PhoneWindow里,补充3里通过windowManager添加显示
    private void reloadAssets() {
        mScreenshotView = (ScreenshotView)
                LayoutInflater.from(mContext).inflate(R.layout.screenshot, null);
//...

        setContentView(mScreenshotView);
    }

    private void setContentView(View contentView) {
        mWindow.setContentView(contentView);
    }
  • 分享,编辑按钮的功能是在3.10里创建的 image.png

3.9.ScreenshotView.java

>1.setChipIntents

imageData数据来源见3.10

    void setChipIntents(ScreenshotController.SavedImageData imageData) {
        mShareChip.setOnClickListener(v -> {
//.
                startSharedTransition(imageData.shareTransition.get());
            }
        });
        mEditChip.setOnClickListener(v -> {
//.
                startSharedTransition(imageData.editTransition.get());//就是3.10.1返回的那个
            }
        });
        mScreenshotPreview.setOnClickListener(v -> {
//.
            startSharedTransition(imageData.editTransition.get());

>2.startSharedTransition

    private void startSharedTransition(ActionTransition transition) {
        try {
            mPendingSharedTransition = true;
            //对于编辑按钮来说,数据就是3.10.1里的editAction对象
            transition.action.actionIntent.send();

            // 淡出非预览UI
            createScreenshotFadeDismissAnimation().start();
        }
    }

3.10.SaveImageInBackgroundTask.java

快照成功以后的share,edit等按钮的功能都在这个类里定义的

>1.createEditAction

    Supplier<ActionTransition> createEditAction(Context context, Resources r, Uri uri,
            boolean smartActionsEnabled) {
        return () -> {
            ActionTransition transition = mSharedElementTransition.get();
            //图片编辑器用的包,可配的,默认是空
            String editorPackage = context.getString(R.string.config_screenshotEditor);
            Intent editIntent = new Intent(Intent.ACTION_EDIT);
            if (!TextUtils.isEmpty(editorPackage)) {
                editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
            }
            editIntent.setDataAndType(uri, "image/png");
            editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

            PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                    context, 0, editIntent, PendingIntent.FLAG_IMMUTABLE,
                    transition.bundle, UserHandle.CURRENT);

            int requestCode = mContext.getUserId();

            PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode,
            //编辑和分享都先交给ActionProxyReceiver好统一处理一些东西
                    new Intent(context, ActionProxyReceiver.class)
                            .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, pendingIntent)
                            .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId)
                            .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED,
                                    smartActionsEnabled)
                            .putExtra(ScreenshotController.EXTRA_OVERRIDE_TRANSITION, true)
                            .setAction(Intent.ACTION_EDIT)
                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
                    UserHandle.SYSTEM);
            Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
                    Icon.createWithResource(r, R.drawable.ic_screenshot_edit),
                    r.getString(com.android.internal.R.string.screenshot_edit), editAction);

            transition.action = editActionBuilder.build();
            return transition;
        };
    }

4.PackageManagerServiceUtils.java

4.1.applyEnforceIntentFilterMatching

    public static void applyEnforceIntentFilterMatching(
            PlatformCompat compat, ComponentResolverApi resolver,
            List<ResolveInfo> resolveInfos, boolean isReceiver,
            Intent intent, String resolvedType, int filterCallingUid) {
            //这行是后加的,早期的代码没有这个,所以打开失败,加了这个就好了,不进行过滤查找
        if (DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.get()) return;

        final Printer logPrinter = DEBUG_INTENT_MATCHING
                ? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM)
                : null;

        for (int i = resolveInfos.size() - 1; i >= 0; --i) {
            final ComponentInfo info = resolveInfos.get(i).getComponentInfo();

            //当调用者是系统、根或相同的应用程序时,不强制过滤器匹配
            if (ActivityManager.checkComponentPermission(null, filterCallingUid,
                    info.applicationInfo.uid, false) == PackageManager.PERMISSION_GRANTED) {
                continue;
            }

            //只有当目标应用的目标SDK >= T时才强制过滤器匹配
            if (!compat.isChangeEnabledInternal(
                    ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, info.applicationInfo)) {
                continue;
            }

            final ParsedMainComponent comp;
            if (info instanceof ActivityInfo) {
                if (isReceiver) {
                    comp = resolver.getReceiver(info.getComponentName());
                } else {
                    comp = resolver.getActivity(info.getComponentName());
                }
            } else if (info instanceof ServiceInfo) {
                comp = resolver.getService(info.getComponentName());
            } else {
                // This shall never happen
                throw new IllegalArgumentException("Unsupported component type");
            }

            if (comp == null || comp.getIntents().isEmpty()) {
                continue;
            }

            boolean match = false;
            for (int j = 0, size = comp.getIntents().size(); j < size; ++j) {
                IntentFilter intentFilter = comp.getIntents().get(j).getIntentFilter();
                //5.1
                if (IntentResolver.intentMatchesFilter(intentFilter, intent, resolvedType)) {
                    match = true;
                    break;
                }
            }
            //1.2.2看到的日志就是这里的,走到这里说明对应的意图不匹配
            if (!match) {
                Slog.w(TAG, "Intent does not match component's intent filter: " + intent);
                Slog.w(TAG, "Access blocked: " + comp.getComponentName());
                if (DEBUG_INTENT_MATCHING) {
                    Slog.v(TAG, "Component intent filters:");
                    comp.getIntents().forEach(f -> f.getIntentFilter().dump(logPrinter, "  "));
                    Slog.v(TAG, "-----------------------------");
                }
                resolveInfos.remove(i);
            }
        }
    }

4.2.ActivityTaskSupervisor.java

>1.startActivityFromRecents

    int startActivityFromRecents(int callingPid, int callingUid, int taskId,
            SafeActivityOptions options) {
            //...

        // ActivityStarter will acquire the lock where the places need, so execute the request
        // outside of the lock.
        try {
            // We need to temporarily disable the explicit intent filter matching enforcement
            // because Task does not store the resolved type of the intent data, causing filter
            // mismatch in certain cases. (b/240373119)
            //这里暂时disable过滤器
            PackageManagerServiceUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(true);
            return mService.getActivityStartController().startActivityInPackage(taskCallingUid,
                    callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,
                    null, 0, 0, options, userId, task, "startActivityFromRecents",
                    false /* validateIncomingUser */, null /* originatingPendingIntent */,
                    false /* allowBackgroundActivityStart */);
        } finally {
        //恢复过滤器
            PackageManagerServiceUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(false);
            synchronized (mService.mGlobalLock) {
                mService.continueWindowLayout();
            }
        }
    }

5.IntentResolver

5.1.intentMatchesFilter

    public static boolean intentMatchesFilter(
            IntentFilter filter, Intent intent, String resolvedType) {

        final int match = filter.match(intent.getAction(), resolvedType, intent.getScheme(),
                intent.getData(), intent.getCategories(), TAG);

        if (match >= 0) {

            return true;
        } else {
            if (debug) {
                final String reason;
                switch (match) {
                    case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
                    case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
                    case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
                    case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
                    default: reason = "unknown reason"; break;
                }
                Slog.v(TAG, "Filter did not match: " + reason);
            }
            return false;
        }
    }

6.IntentFilter.java

6.1.match

public final int match(String action, String type, String scheme,
        Uri data, Set<String> categories, String logTag) {
    return match(action, type, scheme, data, categories, logTag, false /*supportWildcards*/,
            null /*ignoreActions*/);
}
  • 依次比较action,type|scheme,catetories
public final int match(String action, String type, String scheme,
        Uri data, Set<String> categories, String logTag, boolean supportWildcards,
        @Nullable Collection<String> ignoreActions) {
        //补充1
    if (action != null && !matchAction(action, supportWildcards, ignoreActions)) {
//没找到对应的action
        return NO_MATCH_ACTION;
    }
//补充3
    int dataMatch = matchData(type, scheme, data, supportWildcards);
    if (dataMatch < 0) {
        return dataMatch;
    }

    String categoryMismatch = matchCategories(categories);
    if (categoryMismatch != null) {

        return NO_MATCH_CATEGORY;
    }
    return dataMatch;
}

>1.matchAction

  • 参考补充1,wildcardSupported是false,ignoreActions是空
private boolean matchAction(String action, boolean wildcardSupported,
        @Nullable Collection<String> ignoreActions) {
    if (wildcardSupported && WILDCARD.equals(action)) {
        if (ignoreActions == null) {
            return !mActions.isEmpty();
        }
        for (int i = mActions.size() - 1; i >= 0; i--) {
            if (!ignoreActions.contains(mActions.get(i))) {
                return true;
            }
        }
        return false;
    }
    if (ignoreActions != null && ignoreActions.contains(action)) {
        return false;
    }
    return hasAction(action);//补充2
}

>2.hasAction

  • 当前的IntentFilter里有这个action就返回true
public final boolean hasAction(String action) {
    return action != null && mActions.contains(action);
}

>3.matchData

private int matchData(String type, String scheme, Uri data, boolean wildcardSupported) {
//参考补充1,不支持通配符
    final boolean wildcardWithMimegroups = wildcardSupported && countMimeGroups() != 0;
    final List<String> types = mDataTypes;//数据可以参考补充4
    final ArrayList<String> schemes = mDataSchemes;

    int match = MATCH_CATEGORY_EMPTY;

//types和schemes都为空的情况
    if (!wildcardWithMimegroups && types == null && schemes == null) {
        return ((type == null && data == null)
            ? (MATCH_CATEGORY_EMPTY+MATCH_ADJUSTMENT_NORMAL) : NO_MATCH_DATA);
    }

//自身schemes不为空
    if (schemes != null) {
        if (schemes.contains(scheme != null ? scheme : "")
                || wildcardSupported && WILDCARD.equals(scheme)) {
            match = MATCH_CATEGORY_SCHEME;
        } else {
            return NO_MATCH_DATA;
        }

        final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts;
        if (schemeSpecificParts != null && data != null) {
            match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart(), wildcardSupported)
                    ? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA;
        }
        if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) {
            // If there isn't any matching ssp, we need to match an authority.
            final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
            if (authorities != null) {
                int authMatch = matchDataAuthority(data, wildcardSupported);
                if (authMatch >= 0) {
                    final ArrayList<PatternMatcher> paths = mDataPaths;
                    if (paths == null) {
                        match = authMatch;
                    } else if (hasDataPath(data.getPath(), wildcardSupported)) {
                        match = MATCH_CATEGORY_PATH;
                    } else {
                        return NO_MATCH_DATA;
                    }
                } else {
                    return NO_MATCH_DATA;
                }
            }
        }
        // If neither an ssp nor an authority matched, we're done.
        if (match == NO_MATCH_DATA) {
            return NO_MATCH_DATA;
        }
    } else {//自身schemes为空,
        //要比较的scheme不是空,也不是content,file,那么认为不匹配
        if (scheme != null && !"".equals(scheme)
                && !"content".equals(scheme)
                && !"file".equals(scheme)
                && !(wildcardSupported && WILDCARD.equals(scheme))) {
            return NO_MATCH_DATA;
        }
    }

    if (wildcardWithMimegroups) {
        return MATCH_CATEGORY_TYPE;
    } else if (types != null) {
        if (findMimeType(type)) {//补充5
            match = MATCH_CATEGORY_TYPE;
        } else {
            return NO_MATCH_TYPE;
        }
    } else {
        // If no MIME types are specified, then we will only match against
        // an Intent that does not have a MIME type.
        if (type != null) {
            return NO_MATCH_TYPE;
        }
    }

    return match + MATCH_ADJUSTMENT_NORMAL;
}

>4.上边的type

指的是下边的mimeType

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />

    <data
        android:mimeType="video/*"
        android:scheme="content" />
    <data
        android:mimeType="video/*"
        android:scheme="file" />
</intent-filter>

>5.findMimeType

    private final boolean findMimeType(String type) {
        final ArrayList<String> t = mDataTypes;

        if (type == null) {
            return false;
        }

        if (t.contains(type)) {
            return true;
        }

        //处理一个想要匹配IntentFilter中所有类型的Intent
        final int typeLength = type.length();
        if (typeLength == 3 && type.equals("*/*")) {
            return !t.isEmpty();
        }

        // 处理这个想要匹配每个Intent类型的IntentFilter
        if (hasPartialTypes() && t.contains("*")) {
            return true;
        }

        final int slashpos = type.indexOf('/');
        if (slashpos > 0) {
            if (hasPartialTypes() && t.contains(type.substring(0, slashpos))) {
                return true;
            }
            if (typeLength == slashpos+2 && type.charAt(slashpos+1) == '*') {
                //走到这里说明数据是 xxx/* 这样的,我们比较星号前边的
                final int numTypes = t.size();
                for (int i = 0; i < numTypes; i++) {
                    final String v = t.get(i);
                    if (type.regionMatches(0, v, 0, slashpos+1)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }