Launcher13 桌面实现长按应用图标弹出卸载按钮 系统应用没有卸载按钮

修改的类

com.android.launcher3.Launcher
com.android.launcher3.popup.SystemShortcut
com.android.launcher3.popup.PopupContainerWithArrow

具体实现步骤
// 首先在SystemShortcut.java中 仿照应用信息增加一个对象

public static final Factory<BaseDraggingActivity> UNINSTALL = UnInstall::new;

public static class UnInstall extends SystemShortcut  {

        public UnInstall(BaseDraggingActivity target, ItemInfo itemInfo) {
            super(R.drawable.ic_uninstall_no_shadow, R.string.uninstall_drop_target_label, target,
                    itemInfo);

        }

        @Override
        public void onClick(View view) {
            dismissTaskMenuView(mTarget);
            ComponentName cn = getUninstallTarget(mItemInfo);
            if (cn == null) {
                // System applications cannot be installed. For now, show a toast explaining that.
                // We may give them the option of disabling apps this way.
                Toast.makeText(mTarget, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                Intent i = Intent.parseUri(mTarget.getString(R.string.delete_package_intent), 0)
                        .setData(Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
                        .putExtra(Intent.EXTRA_USER, mItemInfo.user);
                mTarget.startActivity(i);
                FileLog.d("Uninstall", "start uninstall activity " + cn.getPackageName());
                return;
            } catch (URISyntaxException e) {
                Log.e("Uninstall", "Failed to parse intent to start uninstall activity for item=" + mItemInfo);
                return;
            }
        }

    }

    /**
     * @return the component name that should be uninstalled or null.
     */
    ComponentName getUninstallTarget(ItemInfo item) {
        Intent intent = null;
        UserHandle user = null;
        if (item != null &&
                item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
            intent = item.getIntent();
            user = item.user;
        }
        if (intent != null) {
            LauncherActivityInfo info = mTarget.getSystemService(LauncherApps.class)
                    .resolveActivity(intent, user);
            if (info != null
                    && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                return info.getComponentName();
            }
        }
        return null;
    }

通过查看APP_INFO的调用可以找到在launcher中 所以我们在launcher中将UNINSTALL增加上


public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
        return Stream.of(APP_INFO, WIDGETS, INSTALL,UNINSTALL);
    }
查看上述getSupportedShortcuts在哪里调用 可以发现在PopupContainerWithArrow的showForIcon方法
public static boolean flag = true;
Launcher launcher = Launcher.getLauncher(icon.getContext());
        if (getOpen(launcher) != null) {
            // There is already an items container open, so don't open this one.
            icon.clearFocus();
            return null;
        }
        ItemInfo item = (ItemInfo) icon.getTag();
        if (!canShow(icon, item)) {
            return null;
        }

        final PopupContainerWithArrow container =
                (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
                        R.layout.popup_container, launcher.getDragLayer(), false);
        container.configureForLauncher(launcher);

        PopupDataProvider popupDataProvider = launcher.getPopupDataProvider();
        // libin 20231116 modify app onlongclick item add uninstall
    	// 这部分主要是用于判断当前长按的应用时候是系统应用
        PackageManager packageManager = icon.getContext().getPackageManager();
        String packageName = item.getTargetComponent().getPackageName();
        Log.d("libin111", "packageName = " + packageName);

        // 判断是否是系统应用
        try {
            ApplicationInfo info = packageManager.getApplicationInfo(packageName, 0);
            Log.d("libin111", "(info.flags & ApplicationInfo.FLAG_SYSTEM) = " + (info.flags & ApplicationInfo.FLAG_SYSTEM));
            if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0){
                flag = false;
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }
        Log.d("libin111", "item flag = " + flag);
        // libin 20231116 modify app onlongclick item add uninstall 
        container.populateAndShow(icon,
                popupDataProvider.getShortcutCountForItem(item),
                popupDataProvider.getNotificationKeysForItem(item),
                launcher.getSupportedShortcuts()
                        .map(s -> {
                            return s.getShortcut(launcher, item);
                        })
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList()));
        launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
        container.requestFocus();
        return container;

上述代码用于判断是否是系统应用 如果是系统应用 在下面的步骤中 将不加载卸载弹框


public void populateAndShow(final BubbleTextView originalIcon, int shortcutCount,
            final List<NotificationKeyData> notificationKeys, List<SystemShortcut> systemShortcuts) {
        mNumNotifications = notificationKeys.size();
        mOriginalIcon = originalIcon;

        boolean hasDeepShortcuts = shortcutCount > 0;
        int containerWidth = (int) getResources().getDimension(R.dimen.bg_popup_item_width);

        // if there are deep shortcuts, we might want to increase the width of shortcuts to fit
        // horizontally laid out system shortcuts.
        if (hasDeepShortcuts) {
            containerWidth = (int) Math.max(containerWidth,
                    systemShortcuts.size() * getResources().getDimension(
                            R.dimen.system_shortcut_header_icon_touch_size));
        }
        // Add views
        if (mNumNotifications > 0) {
            // Add notification entries
            if (mNotificationContainer == null) {
                mNotificationContainer = findViewById(R.id.notification_container);
                mNotificationContainer.setVisibility(VISIBLE);
            }
            View.inflate(getContext(), R.layout.notification_content, mNotificationContainer);
            mNotificationItemView = new NotificationItemView(this, mNotificationContainer);
            updateNotificationHeader();
        }
        int viewsToFlip = getChildCount();
        mSystemShortcutContainer = this;
        if (mDeepShortcutContainer == null) {
            mDeepShortcutContainer = findViewById(R.id.deep_shortcuts_container);
        }
        if (hasDeepShortcuts) {
            mDeepShortcutContainer.setVisibility(View.VISIBLE);

            if (mNotificationItemView != null) {
                mNotificationItemView.addGutter();
            }

            for (int i = shortcutCount; i > 0; i--) {
                DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut, mDeepShortcutContainer);
                v.getLayoutParams().width = containerWidth;
                mShortcuts.add(v);
            }
            updateHiddenShortcuts();

            if (!systemShortcuts.isEmpty()) {
                for (SystemShortcut shortcut : systemShortcuts) {
                    if (shortcut instanceof SystemShortcut.Widgets) {
                        if (mWidgetContainer == null) {
                            mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
                                    this);
                        }
                        initializeSystemShortcut(R.layout.system_shortcut, mWidgetContainer,
                                shortcut);
                    }
                }
                mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);

                for (SystemShortcut shortcut : systemShortcuts) {
                    if (!(shortcut instanceof SystemShortcut.Widgets)) {
                        // 此处修改 此处的情况是应用除了应用信息之外还有其他快捷操作的情况下会走 比如时钟 日历啥的
                        // 首先判断当前的弹框是否是卸载 如果不是卸载则直接加载即可 如果是卸载 再判断是否是系统应用
                        // 如果是系统应用 我们上面已经判断过 将flag设置为false 此时if条件不成立 不添加菜单 如果不是系统应用
                        // flag默认为true 所以条件成立 会添加
                        if (!(shortcut instanceof SystemShortcut.UnInstall) || flag) {
                            initializeSystemShortcut(
                                    R.layout.system_shortcut_icon_only, mSystemShortcutContainer,
                                    shortcut);
                        }
                    }
                }
            }
        } else {
            mDeepShortcutContainer.setVisibility(View.GONE);
            if (!systemShortcuts.isEmpty()) {
                if (mNotificationItemView != null) {
                    mNotificationItemView.addGutter();
                }
                // 此处的情况与上面的完全一样 只是此处的是没有其他快捷方式的时候会走 
                for (SystemShortcut shortcut : systemShortcuts) {
                    Log.d("libin111", "flag last = " + flag);
                    if (!(shortcut instanceof SystemShortcut.UnInstall) || flag) {
                        initializeSystemShortcut(R.layout.system_shortcut, this, shortcut);
                    }
                }
            }
        }
        // 上面执行完之后将flag重新设置为true 下次长按应用时再判断 默认就是true的 
        flag = true;

        reorderAndShow(viewsToFlip);

        ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            setAccessibilityPaneTitle(getTitleForAccessibility());
        }

        mOriginalIcon.setForceHideDot(true);

        // All views are added. Animate layout from now on.
        setLayoutTransition(new LayoutTransition());

        // Load the shortcuts on a background thread and update the container as it animates.
        MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(PopupPopulator.createUpdateRunnable(
                mLauncher, originalItemInfo, new Handler(Looper.getMainLooper()),
                this, mShortcuts, notificationKeys));
    }
 

最后再将下面的代码注释 否则可能会有某些系统应用有闪烁动画


 // If using the expanded system shortcut (as opposed to just the icon), we need
                    // to reopen the container to ensure measurements etc. all work out. While this
                    // could be quite janky, in practice the user would typically see a small
                    // flicker as the animation restarts partway through, and this is a very rare
                    // edge case anyway.
//                    close(false);
//                    PopupContainerWithArrow.showForIcon(mOriginalIcon);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值