Aandroid 应用icon动态加载到launcher方法及framework分析

Android launcher动态加载应用icon的方法


在android 应用开发中,我们会遇到应用icon需要动态加载到launcher中的问题。
实现的方法是:

private PackageManager pm;
pm = context.getPackageManager();
pm.setComponentEnabledSetting(new ComponentName(context,"com.uid.pid.New1MainActivity"),PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP);//加载到launcher中

pm.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
        PackageManager.DONT_KILL_APP);//从launcher中remove

这个setComponentEnabledSetting 具体是怎么工作的,我们通过framework源码可以知道:

PackageManagerService.java

@Override
public void setComponentEnabledSetting(ComponentName componentName,
        int newState, int flags, int userId) {
    if (!sUserManager.exists(userId)) return;
    /* SPRD: update label and icon for app @{ */
    String packege = componentName.getPackageName();
    Log.w(TAG, packege+" == "+newState+" == "+flags+" "+userId);
    if(packege.startsWith("com.android.stk")){
        isOpen = true;
    }
    /* @} */
    Log.d(TAG, "kings:packageName=" + componentName.getPackageName()
            + ", className=" + componentName.getClassName());
    setEnabledSetting(componentName.getPackageName(),
            componentName.getClassName(), newState, flags, userId, null);
}

>

    private void setEnabledSetting(final String packageName, String className, int newState,
        final int flags, int userId, String callingPackage) {
    if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
          || newState == COMPONENT_ENABLED_STATE_ENABLED
          || newState == COMPONENT_ENABLED_STATE_DISABLED
          || newState == COMPONENT_ENABLED_STATE_DISABLED_USER
          || newState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
        throw new IllegalArgumentException("Invalid new component state: "
                + newState);
    }
        ...
        scheduleWritePackageRestrictionsLocked(userId);
        ...
    }

    void scheduleWritePackageRestrictionsLocked(int userId) {
        if (!sUserManager.exists(userId)) return;
        mDirtyUsers.add(userId);
        if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
            mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
        }
    }

    case WRITE_PACKAGE_RESTRICTIONS: {
        Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
        synchronized (mPackages) {
            removeMessages(WRITE_PACKAGE_RESTRICTIONS);
            for (int userId : mDirtyUsers) {
                mSettings.writePackageRestrictionsLPr(userId);
            }
            mDirtyUsers.clear();
        }
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    } break;

从上面可以知道最终调用Settings.java中的writePackageRestrictionsLPr()来实现。

SettingS.java

void writePackageRestrictionsLPr(int userId) {
    if (DEBUG_MU) {
        Log.i(TAG, "Writing package restrictions for user=" + userId);
    }
    // Keep the old stopped packages around until we know the new ones have
    // been successfully written.
    File userPackagesStateFile = getUserPackagesStateFile(userId);
    File backupFile = getUserPackagesStateBackupFile(userId);
    new File(userPackagesStateFile.getParent()).mkdirs();
    if (userPackagesStateFile.exists()) {
        // Presence of backup settings file indicates that we failed
        // to persist packages earlier. So preserve the older
        // backup for future reference since the current packages
        // might have been corrupted.
        if (!backupFile.exists()) {
            if (!userPackagesStateFile.renameTo(backupFile)) {
                Slog.wtf(PackageManagerService.TAG,
                        "Unable to backup user packages state file, "
                        + "current changes will be lost at reboot");
                return;
            }
        } else {
            userPackagesStateFile.delete();
            Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
        }
    }

    try {
        final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile);
        final BufferedOutputStream str = new BufferedOutputStream(fstr);

        final XmlSerializer serializer = new FastXmlSerializer();
        serializer.setOutput(str, StandardCharsets.UTF_8.name());
        serializer.startDocument(null, true);
        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);

        serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);

        for (final PackageSetting pkg : mPackages.values()) {
            PackageUserState ustate = pkg.readUserState(userId);
            if (ustate.stopped || ustate.notLaunched || !ustate.installed
                    || ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
                    || ustate.hidden
                    || (ustate.enabledComponents != null
                            && ustate.enabledComponents.size() > 0)
                    || (ustate.disabledComponents != null
                            && ustate.disabledComponents.size() > 0)
                    || ustate.blockUninstall
                    || (ustate.domainVerificationStatus !=
                        PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED)) {
                serializer.startTag(null, TAG_PACKAGE);
                serializer.attribute(null, ATTR_NAME, pkg.name);
                if (DEBUG_MU) Log.i(TAG, "  pkg=" + pkg.name + ", state=" + ustate.enabled);

                if (!ustate.installed) {
                    serializer.attribute(null, ATTR_INSTALLED, "false");
                }
                if (ustate.stopped) {
                    serializer.attribute(null, ATTR_STOPPED, "true");
                }
                if (ustate.notLaunched) {
                    serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
                }
                if (ustate.hidden) {
                    serializer.attribute(null, ATTR_HIDDEN, "true");
                }
                if (ustate.blockUninstall) {
                    serializer.attribute(null, ATTR_BLOCK_UNINSTALL, "true");
                }
                if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
                    serializer.attribute(null, ATTR_ENABLED,
                            Integer.toString(ustate.enabled));
                    if (ustate.lastDisableAppCaller != null) {
                        serializer.attribute(null, ATTR_ENABLED_CALLER,
                                ustate.lastDisableAppCaller);
                    }
                }
                if (ustate.domainVerificationStatus !=
                        PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
                    serializer.attribute(null, ATTR_DOMAIN_VERIFICATON_STATE,
                            Integer.toString(ustate.domainVerificationStatus));
                }
                if (ustate.appLinkGeneration != 0) {
                    serializer.attribute(null, ATTR_APP_LINK_GENERATION,
                            Integer.toString(ustate.appLinkGeneration));
                }
                if (ustate.enabledComponents != null
                        && ustate.enabledComponents.size() > 0) {
                    serializer.startTag(null, TAG_ENABLED_COMPONENTS);
                    for (final String name : ustate.enabledComponents) {
                        serializer.startTag(null, TAG_ITEM);
                        serializer.attribute(null, ATTR_NAME, name);
                        serializer.endTag(null, TAG_ITEM);
                    }
                    serializer.endTag(null, TAG_ENABLED_COMPONENTS);
                }
                if (ustate.disabledComponents != null
                        && ustate.disabledComponents.size() > 0) {
                    serializer.startTag(null, TAG_DISABLED_COMPONENTS);
                    for (final String name : ustate.disabledComponents) {
                        serializer.startTag(null, TAG_ITEM);
                        serializer.attribute(null, ATTR_NAME, name);
                        serializer.endTag(null, TAG_ITEM);
                    }
                    serializer.endTag(null, TAG_DISABLED_COMPONENTS);
                }

                serializer.endTag(null, TAG_PACKAGE);
            }
        }

        writePreferredActivitiesLPr(serializer, userId, true);
        writePersistentPreferredActivitiesLPr(serializer, userId);
        writeCrossProfileIntentFiltersLPr(serializer, userId);
        writeDefaultAppsLPr(serializer, userId);

        serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);

        serializer.endDocument();

        str.flush();
        FileUtils.sync(fstr);
        str.close();

        // New settings successfully written, old ones are no longer
        // needed.
        backupFile.delete();
        FileUtils.setPermissions(userPackagesStateFile.toString(),
                FileUtils.S_IRUSR|FileUtils.S_IWUSR
                |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
                -1, -1);

        // Done, all is good!
        return;
    } catch(java.io.IOException e) {
        Slog.wtf(PackageManagerService.TAG,
                "Unable to write package manager user packages state, "
                + " current changes will be lost at reboot", e);
    }

    // Clean up partially written files
    if (userPackagesStateFile.exists()) {
        if (!userPackagesStateFile.delete()) {
            Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: "
                    + mStoppedPackagesFilename);
        }
    }
}

通过上面接口发现,android最终将这些componame 保存到手机系统/data/system/users/0/package-restrictions.xml 中

    <pkg name="com.uid.pid">
    <enabled-components>
        <item name="com.uid.pid.New1MainActivity" />
        <item name="com.uid.pid.SecondActivity" />
    </enabled-components>
    <disabled-components>
        <item name="com.uid.pid.MainActivity" />
        <item name="com.uid.pid.New2MainActivity" />
    </disabled-components>
    </pkg>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值