美文网首页
Android 启动 应用程序详情AppInfo(AppDeta

Android 启动 应用程序详情AppInfo(AppDeta

作者: 行走中的3卡 | 来源:发表于2023-07-18 10:16 被阅读0次

    在Launcher (桌面)上,长按应用图标然后点击 右上角的 应用详情 按钮,
    将会进入 该 应用的详情 界面。
    这个过程将会涉及 Client (Launcher App) -> App API(LauncherApps ) -> Framework API(LauncherAppsService)
    下面将以 LauncherApps -> LauncherAppsService 深入Framework 分析,然后再看在 客服端的调用

    1. 客户端接口 LauncherApps.startAppDetailsActivity

    frameworks/base/core/java/android/content/pm/LauncherApps.java

    @SystemService(Context.LAUNCHER_APPS_SERVICE)
    public class LauncherApps {
    
        /** @hide */
        public LauncherApps(Context context, ILauncherApps service) {
            mContext = context;
            mService = service;
            mPm = context.getPackageManager();
            mUserManager = context.getSystemService(UserManager.class);
        }
    
        /**
         * Starts the settings activity to show the application details for a
         * package in the specified profile.
         *
         * @param component The ComponentName of the package to launch settings for.
         * @param user The UserHandle of the profile
         * @param sourceBounds The Rect containing the source bounds of the clicked icon
         * @param opts Options to pass to startActivity
         */
        public void startAppDetailsActivity(ComponentName component, UserHandle user,
                Rect sourceBounds, Bundle opts) {
            logErrorForInvalidProfileAccess(user);
            try {
                mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
                        mContext.getPackageName(), mContext.getAttributionTag(),
                        component, sourceBounds, opts, user);
            } catch (RemoteException re) {
                throw re.rethrowFromSystemServer();
            }
        }
    

    客户端 可以通过 context.getSystemService(Context.LAUNCHER_APPS_SERVICE)
    或者 context.getSystemService(LauncherApps.class)
    获取到LauncherApps 实例对象.

    2. AIDL 接口 ILauncherApps.showAppDetailsAsUser

    上面的代码可以看出,实际上是通过 AIDL 接口进行调用方法 showAppDetailsAsUser,即:
    frameworks/base/core/java/android/content/pm/ILauncherApps.aidl

    interface ILauncherApps {
        ....
        void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
                String callingFeatureId, in ComponentName component, in Rect sourceBounds,
                in Bundle opts, in UserHandle user);    
    }
    

    3. system_server 实现 LauncherAppsService.showAppDetailsAsUser

    showAppDetailsAsUser 最终的实现是在 system_server 进程里的
    frameworks/base/services/core/java/com/android/server/pm/LauncherAppsService.java

            @Override
            public void showAppDetailsAsUser(IApplicationThread caller,
                    String callingPackage, String callingFeatureId, ComponentName component,
                    Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException {
                if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) {
                    return;
                }
    
                final Intent intent;
                final long ident = Binder.clearCallingIdentity();
                try {
                    String packageName = component.getPackageName();
                    int uId = -1;
                    try {
                        uId = mContext.getPackageManager().getApplicationInfo(
                                packageName, PackageManager.MATCH_ANY_USER).uid;
                    } catch (PackageManager.NameNotFoundException e) {
                        Log.d(TAG, "package not found: " + e);
                    }
                    intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                            Uri.fromParts("package", packageName, null));
                    intent.putExtra("uId", uId);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    intent.setSourceBounds(sourceBounds);
                } finally {
                    Binder.restoreCallingIdentity(ident);
                }
                mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage,
                        callingFeatureId, intent, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK,
                        opts, user.getIdentifier());
            }
    

    可以看出,最后调用的其实是 ATMS 的 startActivityAsUser 方法

    4. PackageManagerHelper. startDetailsActivityForInfo 客户端封装接口

    packages/apps/Launcher3/src/com/android/launcher3/util/PackageManagerHelper.java

        /**
         * Starts the details activity for {@code info}
         */
        public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) {
            if (info instanceof ItemInfoWithIcon
                    && (((ItemInfoWithIcon) info).runtimeStatusFlags
                        & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
                ItemInfoWithIcon appInfo = (ItemInfoWithIcon) info;
                mContext.startActivity(new PackageManagerHelper(mContext)
                        .getMarketIntent(appInfo.getTargetComponent().getPackageName()));
                return;
            }
            ComponentName componentName = null;
            if (info instanceof AppInfo) {
                componentName = ((AppInfo) info).componentName;
            } else if (info instanceof WorkspaceItemInfo) {
                componentName = info.getTargetComponent();
            } else if (info instanceof PendingAddItemInfo) {
                componentName = ((PendingAddItemInfo) info).componentName;
            } else if (info instanceof LauncherAppWidgetInfo) {
                componentName = ((LauncherAppWidgetInfo) info).providerName;
            }
            if (componentName != null) {
                try {
                    mLauncherApps.startAppDetailsActivity(componentName, info.user, sourceBounds, opts);
                } catch (SecurityException | ActivityNotFoundException e) {
                    Toast.makeText(mContext, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                    Log.e(TAG, "Unable to launch settings", e);
                }
            }
        }
    

    可以看出,最终调用的就是 LauncherApps.startAppDetailsActivity,
    只不过这里对 具体的 组件名称 进行了解析

    5. 应用详情 进入点 AppInfo.onClick

    其中,AppInfo 是 SystemShortcut 的子类以及内部类。
    packages/apps/Launcher3/src/com/android/launcher3/popup/SystemShortcut.java

    /**
     * Represents a system shortcut for a given app. The shortcut should have a label and icon, and an
     * onClickListener that depends on the item that the shortcut services.
     *
     * Example system shortcuts, defined as inner classes, include Widgets and AppInfo.
     * @param <T>
     */
    public abstract class SystemShortcut<T extends Context & ActivityContext> extends ItemInfo
            implements View.OnClickListener {
            ...
    
        public static class AppInfo<T extends Context & ActivityContext> extends SystemShortcut<T> {
    
            @Nullable
            private SplitAccessibilityInfo mSplitA11yInfo;
    
            public AppInfo(T target, ItemInfo itemInfo, View originalView) {
                super(R.drawable.ic_info_no_shadow, R.string.app_info_drop_target_label, target,
                        itemInfo, originalView);
            }
            
            @Override
            public void onClick(View view) {
                dismissTaskMenuView(mTarget);
                Rect sourceBounds = Utilities.getViewBounds(view);
                new PackageManagerHelper(mTarget).startDetailsActivityForInfo(
                        mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
                mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
                        .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP);
            }       
    }
    

    可以看到,这里 onClick 函数调用了上面的 PackageManagerHelper.startDetailsActivityForInfo。
    当然,注释里也说明了,这个 AppInfo 只是一个例子,Launcher App也可以自定义。

    参考:Android 13 源码

    相关文章

      网友评论

          本文标题:Android 启动 应用程序详情AppInfo(AppDeta

          本文链接:https://www.haomeiwen.com/subject/kqvgudtx.html