ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

修改Launcher3图标,给图标加蒙层或影藏图标

2021-09-09 16:06:48  阅读:309  来源: 互联网

标签:info null get int 加蒙层 bitmap Launcher3 图标 icon


最近项目需求修改Launcher3的源码,需求是给图标加上蒙层。

阅读源码发现图标的缓存是在com/android.launcher3/graphics目录下的LauncherIcons.java类中修改。

在createIconBitmap()方法中

修改之前的代码:

public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
        synchronized (sCanvas) {
            final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
            int width = iconBitmapSize;
            int height = iconBitmapSize;

            if (icon instanceof PaintDrawable) {
                PaintDrawable painter = (PaintDrawable) icon;
                painter.setIntrinsicWidth(width);
                painter.setIntrinsicHeight(height);
            } else if (icon instanceof BitmapDrawable) {
                // Ensure the bitmap has a density.
                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
                Bitmap bitmap = bitmapDrawable.getBitmap();
                if (bitmap != null && bitmap.getDensity() == Bitmap.DENSITY_NONE) {
                    bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
                }
            }

            int sourceWidth = icon.getIntrinsicWidth();
            int sourceHeight = icon.getIntrinsicHeight();
            if (sourceWidth > 0 && sourceHeight > 0) {
                // Scale the icon proportionally to the icon dimensions
                final float ratio = (float) sourceWidth / sourceHeight;
                if (sourceWidth > sourceHeight) {
                    height = (int) (width / ratio);
                } else if (sourceHeight > sourceWidth) {
                    width = (int) (height * ratio);
                }
            }
            // no intrinsic size --> use default size
            int textureWidth = iconBitmapSize;
            int textureHeight = iconBitmapSize;

            Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
                    Bitmap.Config.ARGB_8888);
            final Canvas canvas = sCanvas;
            canvas.setBitmap(bitmap);

            final int left = (textureWidth - width) / 2;
            final int top = (textureHeight - height) / 2;

            sOldBounds.set(icon.getBounds());
            if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
                int offset = Math.max((int) (ShadowGenerator.BLUR_FACTOR * iconBitmapSize),
                        Math.min(left, top));
                int size = Math.max(width, height);
                icon.setBounds(offset, offset, size, size);
            } else {
                icon.setBounds(left, top, left + width, top + height);
            }
            canvas.save(Canvas.MATRIX_SAVE_FLAG);
            canvas.scale(scale, scale, textureWidth / 2, textureHeight / 2);
            icon.draw(canvas);
            canvas.restore();
            icon.setBounds(sOldBounds);
            canvas.setBitmap(null);
            return bitmap;
        }
    }

只需要在绘制完图标后再一个Bitmap就行了:

Bitmap bitmapStop = BitmapFactory.decodeResource(context.getResources(), R.mipmap.icon_stop);
            Rect rect = new Rect(left, top, left + width, top + height);
            canvas.drawBitmap(bitmapStop, null, rect, new Paint());

修改完之后代码:

public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
        synchronized (sCanvas) {
            final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
            int width = iconBitmapSize;
            int height = iconBitmapSize;
            if (icon instanceof PaintDrawable) {
                PaintDrawable painter = (PaintDrawable) icon;
                painter.setIntrinsicWidth(width);
                painter.setIntrinsicHeight(height);
            } else if (icon instanceof BitmapDrawable) {
                // Ensure the bitmap has a density.
                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
                Bitmap bitmap = bitmapDrawable.getBitmap();
                if (bitmap != null && bitmap.getDensity() == Bitmap.DENSITY_NONE) {
                    bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
                }
            }

            int sourceWidth = icon.getIntrinsicWidth();
            int sourceHeight = icon.getIntrinsicHeight();
            if (sourceWidth > 0 && sourceHeight > 0) {
                // Scale the icon proportionally to the icon dimensions
                final float ratio = (float) sourceWidth / sourceHeight;
                if (sourceWidth > sourceHeight) {
                    height = (int) (width / ratio);
                } else if (sourceHeight > sourceWidth) {
                    width = (int) (height * ratio);
                }
            }
            // no intrinsic size --> use default size
            int textureWidth = iconBitmapSize;
            int textureHeight = iconBitmapSize;

            Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
                    Bitmap.Config.ARGB_8888);
            final Canvas canvas = sCanvas;
            canvas.setBitmap(bitmap);

            final int left = (textureWidth - width) / 2;
            final int top = (textureHeight - height) / 2;

            sOldBounds.set(icon.getBounds());
            if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
                int offset = Math.max((int) (ShadowGenerator.BLUR_FACTOR * iconBitmapSize),
                        Math.min(left, top));
                int size = Math.max(width, height);
                icon.setBounds(offset, offset, size, size);
            } else {
                icon.setBounds(left, top, left + width, top + height);
            }
            canvas.save(Canvas.MATRIX_SAVE_FLAG);
            canvas.scale(scale, scale, textureWidth / 2, textureHeight / 2);
            icon.draw(canvas);
            // TODO: 2021/7/27 添加背景
            Bitmap bitmapStop = BitmapFactory.decodeResource(context.getResources(), R.mipmap.icon_stop);
            Rect rect = new Rect(left, top, left + width, top + height);
            canvas.drawBitmap(bitmapStop, null, rect, new Paint());
            canvas.restore();
            icon.setBounds(sOldBounds);
            canvas.setBitmap(null);
            return bitmap;
        }
    }

此处可以通过包名判断哪些应用图标需要添加蒙层。

而我们的需求是需要动态变换图标 通过网络请求获取到需要添加蒙层的应用包名,然后进行区分添加不同的蒙层。

在网络请求中调用LauncherModel的updateSessionDisplayInfo()方法传递的参数是需要修改的图标包名

mModel.updateSessionDisplayInfo("需要修改的包名");
    public void updateSessionDisplayInfo(final String packageName) {
        HashSet<String> packages = new HashSet<>();
        packages.add(packageName);
        enqueueModelUpdateTask(new CacheDataUpdatedTask(
                CacheDataUpdatedTask.OP_SESSION_UPDATE, Process.myUserHandle(), packages));
    }

该方法会调用CacheDataUpdatedTask类的execute()方法

    @Override
    public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
        IconCache iconCache = app.getIconCache();

        final ArrayList<AppInfo> updatedApps = new ArrayList<>();

        ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();
        synchronized (dataModel) {
            for (ItemInfo info : dataModel.itemsIdMap) {
                if (info instanceof ShortcutInfo && mUser.equals(info.user)) {
                    ShortcutInfo si = (ShortcutInfo) info;
                    ComponentName cn = si.getTargetComponent();
                    if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
                            && isValidShortcut(si) && cn != null
                            && mPackages.contains(cn.getPackageName())) {
                        iconCache.getTitleAndIcon(si, si.usingLowResIcon);
                        updatedShortcuts.add(si);
                    }
                }
            }
            apps.updateIconsAndLabels(mPackages, mUser, updatedApps);
        }
        bindUpdatedShortcuts(updatedShortcuts, mUser);

        if (!updatedApps.isEmpty()) {
            scheduleCallbackTask(new CallbackTask() {
                @Override
                public void execute(Callbacks callbacks) {
                    callbacks.bindAppsAddedOrUpdated(updatedApps);
                }
            });
        }
    }

然后就会调用CacheDataUpdatedTask类的

apps.updateIconsAndLabels(mPackages, mUser, updatedApps);方法

在往后就会调用AllAppsList类的updateIconsAndLabels()方法

 public void updateIconsAndLabels(HashSet<String> packages, UserHandle user,
            ArrayList<AppInfo> outUpdates) {
        for (AppInfo info : data) {
            if (info.user.equals(user) && packages.contains(info.componentName.getPackageName())) {
                mIconCache.updateTitleAndIcon(info);
                outUpdates.add(info);
            }
        }
    }

最终走到IconCache类的cacheLocked()方法中

protected CacheEntry cacheLocked(
            @NonNull ComponentName componentName,
            @NonNull Provider<LauncherActivityInfo> infoProvider,
            UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
        Preconditions.assertWorkerThread();
        ComponentKey cacheKey = new ComponentKey(componentName, user);
        CacheEntry entry = mCache.get(cacheKey);
        if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
            entry = new CacheEntry();
            mCache.put(cacheKey, entry);
            // Check the DB first.
            LauncherActivityInfo info = null;
            boolean providerFetchedOnce = false;
            if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
                info = infoProvider.get();
                providerFetchedOnce = true;
                if (info != null) {
                    List<DevGetallAppStatus.AppsBean> appsBeans1 = new ArrayList<>();
                    List<DevGetallAppStatus.AppsBean> appsBeans2 = new ArrayList<>();
                    if (Launcher.allAppStatus != null && Launcher.allAppStatus != null && Launcher.allAppStatus.size() > 0) {
                        for (int i = 0; i < Launcher.allAppStatus.size(); i++) {
                            if (Launcher.allAppStatus.get(i).enable.equals("0")) {
                                appsBeans1.add(Launcher.allAppStatus.get(i));
                            } else if (Launcher.allAppStatus.get(i).enable.equals("2")) {
                                appsBeans2.add(Launcher.allAppStatus.get(i));
                            }
                        }
                    }
                    entry.icon = LauncherIcons.createBadgedIconBitmap(
                            getFullResIcon(info), info.getUser(), mContext,
                            infoProvider.get().getApplicationInfo().targetSdkVersion);
                    for (int i = 0; i < appsBeans1.size(); i++) {
                        if (info.getComponentName().getPackageName().equals(appsBeans1.get(i).packageName)) {
                            entry.icon = LauncherIcons.createBadgedIconBitmapRed(
                                    getFullResIcon(info), info.getUser(), mContext,
                                    infoProvider.get().getApplicationInfo().targetSdkVersion);
                        }
                    }
                    for (int i = 0; i < appsBeans2.size(); i++) {
                        if (info.getComponentName().getPackageName().equals(appsBeans2.get(i).packageName)) {
                            entry.icon = LauncherIcons.createBadgedIconBitmapGreen(
                                    getFullResIcon(info), info.getUser(), mContext,
                                    infoProvider.get().getApplicationInfo().targetSdkVersion);
                        }
                    }
                } else {
                    if (usePackageIcon) {
                        CacheEntry packageEntry = getEntryForPackageLocked(
                                componentName.getPackageName(), user, false);
                        if (packageEntry != null) {
                            if (DEBUG) Log.d(TAG, "using package default icon for " +
                                    componentName.toShortString());
                            entry.icon = packageEntry.icon;
                            entry.title = packageEntry.title;
                            entry.contentDescription = packageEntry.contentDescription;
                        }
                    }
                    if (entry.icon == null) {
                        if (DEBUG) Log.d(TAG, "using default icon for " +
                                componentName.toShortString());
                        entry.icon = getDefaultIcon(user);
                    }
                }
            }

            if (TextUtils.isEmpty(entry.title)) {
                if (info == null && !providerFetchedOnce) {
                    info = infoProvider.get();
                    providerFetchedOnce = true;
                }
                if (info != null) {
                    entry.title = info.getLabel();
                    entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
                }
            }
        }
        if (Launcher.changeAppsBeans.size() > 0) {
            if (infoProvider.get() != null && infoProvider.get().getComponentName() != null) {
                LauncherActivityInfo info = infoProvider.get();
                List<DevGetallAppStatus.AppsBean> appsBeans1 = new ArrayList<>();
                List<DevGetallAppStatus.AppsBean> appsBeans2 = new ArrayList<>();
                List<DevGetallAppStatus.AppsBean> appsBeans3 = new ArrayList<>();
                for (int i = 0; i < Launcher.changeAppsBeans.size(); i++) {
                    if (Launcher.changeAppsBeans.get(i).enable.equals("0")) {
                        appsBeans1.add(Launcher.changeAppsBeans.get(i));
                    } else if (Launcher.changeAppsBeans.get(i).enable.equals("2")) {
                        appsBeans2.add(Launcher.changeAppsBeans.get(i));
                    } else {
                        appsBeans3.add(Launcher.changeAppsBeans.get(i));
                    }
                }
                for (int i = 0; i < appsBeans1.size(); i++) {
                    if (info.getComponentName().getPackageName().equals(appsBeans1.get(i).packageName)) {
                        entry.icon = LauncherIcons.createBadgedIconBitmapRed(
                                getFullResIcon(info), info.getUser(), mContext,
                                infoProvider.get().getApplicationInfo().targetSdkVersion);
                        Log.i("lee", "执行完list1禁用修改" + info.getComponentName().getPackageName());
                    }
                }
                for (int i = 0; i < appsBeans2.size(); i++) {
                    if (info.getComponentName().getPackageName().equals(appsBeans2.get(i).packageName)) {
                        entry.icon = LauncherIcons.createBadgedIconBitmapGreen(
                                getFullResIcon(info), info.getUser(), mContext,
                                infoProvider.get().getApplicationInfo().targetSdkVersion);
                        Log.i("lee", "执行完list2限时修改" + info.getComponentName().getPackageName());
                    }
                }
                for (int i = 0; i < appsBeans3.size(); i++) {
                    if (info.getComponentName().getPackageName().equals(appsBeans3.get(i).packageName)) {
                        entry.icon = LauncherIcons.createBadgedIconBitmap(
                                getFullResIcon(info), info.getUser(), mContext,
                                infoProvider.get().getApplicationInfo().targetSdkVersion);
                        Log.i("lee", "执行完list3自由修改" + info.getComponentName().getPackageName());
                    }
                }
                Launcher.changeAppsBeans.clear();
            }
        }
        return entry;
    }

主要逻辑在此处通过包名判断修改数据列表

LauncherActivityInfo info = infoProvider.get();
                List<DevGetallAppStatus.AppsBean> appsBeans1 = new ArrayList<>();
                List<DevGetallAppStatus.AppsBean> appsBeans2 = new ArrayList<>();
                List<DevGetallAppStatus.AppsBean> appsBeans3 = new ArrayList<>();
                for (int i = 0; i < Launcher.changeAppsBeans.size(); i++) {
                    if (Launcher.changeAppsBeans.get(i).enable.equals("0")) {
                        appsBeans1.add(Launcher.changeAppsBeans.get(i));
                    } else if (Launcher.changeAppsBeans.get(i).enable.equals("2")) {
                        appsBeans2.add(Launcher.changeAppsBeans.get(i));
                    } else {
                        appsBeans3.add(Launcher.changeAppsBeans.get(i));
                    }
                }

然后复制两个LauncherIcons类中的createBadgedIconBitmap()方法 如果有3中蒙层就复制3个(比较笨和懒的方法)

就会调用以下方法

public static Bitmap createBadgedIconBitmap(
            Drawable icon, UserHandle user, Context context, int iconAppTargetSdk) {

        IconNormalizer normalizer;
        float scale = 1f;
        if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
            normalizer = IconNormalizer.getInstance(context);
            if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) {
                boolean[] outShape = new boolean[1];
                AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
                        context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
                dr.setBounds(0, 0, 1, 1);
                scale = normalizer.getScale(icon, null, dr.getIconMask(), outShape);
                if (FeatureFlags.LEGACY_ICON_TREATMENT &&
                        !outShape[0]) {
                    Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale);
                    if (wrappedIcon != icon) {
                        icon = wrappedIcon;
                        scale = normalizer.getScale(icon, null, null, null);
                    }
                }
            } else {
                scale = normalizer.getScale(icon, null, null, null);
            }
        }
        Bitmap bitmap = createIconBitmap(icon, context, scale);
        if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.ATLEAST_OREO &&
                icon instanceof AdaptiveIconDrawable) {
            bitmap = ShadowGenerator.getInstance(context).recreateIcon(bitmap);
        }
        return badgeIconForUser(bitmap, user, context);
    }

最终调用一开始说的方法:

public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
        synchronized (sCanvas) {
            final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
            int width = iconBitmapSize;
            int height = iconBitmapSize;

            if (icon instanceof PaintDrawable) {
                PaintDrawable painter = (PaintDrawable) icon;
                painter.setIntrinsicWidth(width);
                painter.setIntrinsicHeight(height);
            } else if (icon instanceof BitmapDrawable) {
                // Ensure the bitmap has a density.
                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
                Bitmap bitmap = bitmapDrawable.getBitmap();
                if (bitmap != null && bitmap.getDensity() == Bitmap.DENSITY_NONE) {
                    bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
                }
            }

            int sourceWidth = icon.getIntrinsicWidth();
            int sourceHeight = icon.getIntrinsicHeight();
            if (sourceWidth > 0 && sourceHeight > 0) {
                // Scale the icon proportionally to the icon dimensions
                final float ratio = (float) sourceWidth / sourceHeight;
                if (sourceWidth > sourceHeight) {
                    height = (int) (width / ratio);
                } else if (sourceHeight > sourceWidth) {
                    width = (int) (height * ratio);
                }
            }
            // no intrinsic size --> use default size
            int textureWidth = iconBitmapSize;
            int textureHeight = iconBitmapSize;

            Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
                    Bitmap.Config.ARGB_8888);
            final Canvas canvas = sCanvas;
            canvas.setBitmap(bitmap);

            final int left = (textureWidth - width) / 2;
            final int top = (textureHeight - height) / 2;

            sOldBounds.set(icon.getBounds());
            if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
                int offset = Math.max((int) (ShadowGenerator.BLUR_FACTOR * iconBitmapSize),
                        Math.min(left, top));
                int size = Math.max(width, height);
                icon.setBounds(offset, offset, size, size);
            } else {
                icon.setBounds(left, top, left + width, top + height);
            }
            canvas.save(Canvas.MATRIX_SAVE_FLAG);
            canvas.scale(scale, scale, textureWidth / 2, textureHeight / 2);
            icon.draw(canvas);
            canvas.restore();
            icon.setBounds(sOldBounds);
            canvas.setBitmap(null);
            return bitmap;
        }
    }

这样就完成了对Launcher3图标的动态添加蒙层。

在提一句影藏某些包名的应用图标就只需要在:
IconCache的cacheLocked()方法中通过包名过滤是否需要展示某些应用图标。

标签:info,null,get,int,加蒙层,bitmap,Launcher3,图标,icon
来源: https://blog.csdn.net/qq77485042/article/details/120202313

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有