修改的类
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);