1.简介
- 主要学习下overview页面底部的两个功能按钮
- 点击screenshot按钮以后的流程,然后快照弹框有2个按钮,可以编辑,分享快照,顺道学习下编辑按钮的逻辑
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里创建的
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;
}