Skip to content

Commit

Permalink
Add uninstall command
Browse files Browse the repository at this point in the history
  • Loading branch information
devycarol committed Aug 7, 2024
1 parent ce80b32 commit 493f47e
Show file tree
Hide file tree
Showing 18 changed files with 141 additions and 24 deletions.
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />

<queries>
<package android:name="com.android.contacts" />
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/net/emilla/AssistActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ private void showDialog(final AlertDialog dialog, final byte chime) {
chime(chime);
}

private void fail(final String message) {
public void fail(final CharSequence message) {
chime(FAIL);
toast(message, true);
}
Expand Down
8 changes: 3 additions & 5 deletions app/src/main/java/net/emilla/commands/CommandOpenInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

import android.app.AlertDialog;
import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;

import net.emilla.AssistActivity;
import net.emilla.R;
Expand All @@ -26,7 +24,7 @@ protected AlertDialog.Builder getAppChooser(final AssistActivity act) {
}

private final Intent mInfoIntent = Apps.newTask(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:" + Apps.PKG));
Apps.pkgUri(Apps.PKG));
private final boolean mUnsafe;

public CommandOpenInfo(final AssistActivity act) {
Expand All @@ -42,8 +40,8 @@ public void run() {
succeed(mInfoIntent);
}

@Override @NonNull
@Override
protected Intent getIntent(final String pkg, final String cls) {
return Apps.newTask(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + pkg));
return Apps.newTask(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Apps.pkgUri(pkg));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
import android.content.Intent;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;

import net.emilla.AssistActivity;
import net.emilla.R;
import net.emilla.utils.Apps;
import net.emilla.utils.Dialogs;

public class CommandOpenApp extends OpenCommand {
public class CommandOpenLaunch extends OpenCommand {
@Override @DrawableRes
public int icon() {
return R.drawable.ic_launch;
Expand All @@ -21,7 +20,7 @@ protected AlertDialog.Builder getAppChooser(final AssistActivity act) {
return Dialogs.appChooser(act, act.getPackageManager(), mAppList);
}

public CommandOpenApp(final AssistActivity act) {
public CommandOpenLaunch(final AssistActivity act) {
super(act, R.string.command_launch, R.string.instruction_app);
}

Expand All @@ -30,7 +29,7 @@ public void run() {
offer(mAppChooser.create());
}

@Override @NonNull
@Override
protected Intent getIntent(final String pkg, final String cls) {
return Apps.launchIntent(pkg, cls);
}
Expand Down
38 changes: 38 additions & 0 deletions app/src/main/java/net/emilla/commands/CommandOpenUninstall.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.emilla.commands;

import android.app.AlertDialog;
import android.content.Intent;

import androidx.annotation.DrawableRes;

import net.emilla.AssistActivity;
import net.emilla.R;
import net.emilla.utils.Apps;
import net.emilla.utils.Dialogs;

public class CommandOpenUninstall extends OpenCommand {
@Override
@DrawableRes
public int icon() {
return R.drawable.ic_uninstall;
}

@Override
protected AlertDialog.Builder getAppChooser(final AssistActivity act) {
return Dialogs.appUninstaller(act, mAppList);
}

public CommandOpenUninstall(final AssistActivity act) {
super(act, R.string.command_uninstall, R.string.instruction_app);
}

@Override
public void run() {
offer(mAppChooser.create());
}

@Override
protected Intent getIntent(final String pkg, final String cls) {
return Apps.uninstallIntent(pkg, mPm);
}
}
3 changes: 2 additions & 1 deletion app/src/main/java/net/emilla/commands/CommandTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public EmillaCommand newCore(final AssistActivity act, final short id) {
case DIAL -> new CommandDial(act);
case SMS -> new CommandSms(act);
case EMAIL -> new CommandEmail(act);
case LAUNCH -> new CommandOpenApp(act);
case LAUNCH -> new CommandOpenLaunch(act);
case SHARE -> new CommandShare(act);
case SETTINGS -> new CommandSettings(act);
// case NOTE -> new CommandNote(act);
Expand All @@ -193,6 +193,7 @@ public EmillaCommand newCore(final AssistActivity act, final short id) {
case WEATHER -> new CatCommandWeather(act);
case VIEW -> new CommandView(act);
case INFO -> new CommandOpenInfo(act);
case UNINSTALL -> new CommandOpenUninstall(act);
case TOAST -> new CommandToast(act);
default -> null;
};
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/java/net/emilla/commands/EmillaCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ public static class Commands {
WEATHER = 16,
VIEW = 17,
INFO = 18,
TOAST = 19,
DUPLICATE = 20;
UNINSTALL = 19,
TOAST = 20,
DUPLICATE = 21;
}

private static final int[] NAMES = {
Expand All @@ -71,6 +72,7 @@ public static class Commands {
R.string.command_weather,
R.string.command_view,
R.string.command_info,
R.string.command_uninstall,
R.string.command_toast
};

Expand Down
10 changes: 5 additions & 5 deletions app/src/main/java/net/emilla/commands/OpenCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import android.content.pm.ResolveInfo;
import android.view.inputmethod.EditorInfo;

import androidx.annotation.NonNull;
import androidx.annotation.StringRes;

import net.emilla.AssistActivity;
Expand All @@ -22,13 +21,15 @@
public abstract class OpenCommand extends CoreCommand {
protected final List<ResolveInfo> mAppList;
protected final AlertDialog.Builder mAppChooser;
protected final PackageManager mPm;

public OpenCommand(final AssistActivity act, @StringRes final int nameId,
@StringRes final int instructionId) {
super(act, nameId, instructionId);

mAppList = act.appList();
mAppChooser = getAppChooser(act);
mPm = act.getPackageManager();
}

protected abstract AlertDialog.Builder getAppChooser(final AssistActivity act);
Expand All @@ -55,14 +56,13 @@ public void run(final String app) {
int prefCount = 0;
int otherCount = 0;

final PackageManager pm = packageManager();
final String lcQuery = app.toLowerCase();
boolean exactMatch = false;

for (int i = 0; i < appCount; ++i) {
ActivityInfo info = mAppList.get(i).activityInfo;

CharSequence label = info.loadLabel(pm);
CharSequence label = info.loadLabel(mPm);
String lcLabel = label.toString().toLowerCase();

if (lcLabel.equals(lcQuery)) { // an exact match will drop all other results
Expand All @@ -77,7 +77,7 @@ public void run(final String app) {

for (++i; i < appCount; ++i) { // continue searching for duplicates only
info = mAppList.get(i).activityInfo;
label = info.loadLabel(pm);
label = info.loadLabel(mPm);
lcLabel = label.toString().toLowerCase();

if (lcLabel.equals(lcQuery)) {
Expand Down Expand Up @@ -121,5 +121,5 @@ public void run(final String app) {
default -> offer(getDialog(prefLabels, prefCount, prefIntents));
}}

protected abstract @NonNull Intent getIntent(final String pkg, final String cls);
protected abstract Intent getIntent(final String pkg, final String cls);
}
2 changes: 1 addition & 1 deletion app/src/main/java/net/emilla/config/SettingsFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ private void setupAccessibilityButtonPref(final PackageManager pm) {
private void setupAppInfoPref(final PackageManager pm) {
final Preference systemAppInfo = requireNonNull(findPreference("app_info"));
final Intent in = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:" + Apps.PKG));
Apps.pkgUri(Apps.PKG));
if (in.resolveActivity(pm) != null) systemAppInfo.setIntent(in);
else systemAppInfo.setVisible(false);
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/net/emilla/settings/Aliases.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class Aliases {
R.array.aliases_weather,
R.array.aliases_view,
R.array.aliases_info,
R.array.aliases_uninstall,
R.array.aliases_toast
};

Expand All @@ -62,6 +63,7 @@ public class Aliases {
"aliases_weather",
"aliases_view",
"aliases_info",
"aliases_uninstall",
"aliases_toast"
};

Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/net/emilla/settings/SettingVals.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ private static short commandId(final String s) {
case "weather" -> WEATHER;
case "view" -> VIEW;
case "info" -> INFO;
case "uninstall" -> UNINSTALL;
case "toast" -> TOAST;
default -> 0;
};
Expand Down
30 changes: 30 additions & 0 deletions app/src/main/java/net/emilla/utils/Apps.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;

import androidx.annotation.NonNull;

Expand Down Expand Up @@ -106,4 +108,32 @@ public static Intent[] intents(final List<ResolveInfo> appList) {
for (final ResolveInfo ri : appList) intents[++i] = launchIntent(ri.activityInfo);
return intents;
}

public static Uri pkgUri(final String pkg) {
return Uri.parse("package:" + pkg);
}

public static Intent uninstallIntent(final String pkg, final PackageManager pm) {
final ApplicationInfo info;
try {
info = pm.getApplicationInfo(pkg, 0);
final boolean uninstallable = (info.flags & ApplicationInfo.FLAG_SYSTEM) == 0;
if (uninstallable) return newTask(ACTION_UNINSTALL_PACKAGE, pkgUri(pkg));
// Todo: ACTION_UNINSTALL_PACKAGE is deprecated.
final Intent appInfo = newTask(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, pkgUri(pkg));
if (appInfo.resolveActivity(pm) != null) return appInfo;
final Intent settings = newTask(Settings.ACTION_SETTINGS);
if (appInfo.resolveActivity(pm) != null) return settings;
} catch (PackageManager.NameNotFoundException ignored) {}
return null;
}

public static Intent[] uninstalls(final List<ResolveInfo> appList, final PackageManager pm) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) return appList.parallelStream()
.map(ri -> uninstallIntent(ri.activityInfo.packageName, pm)).toArray(Intent[]::new);
final Intent[] intents = new Intent[appList.size()];
int i = -1;
for (final ResolveInfo ri : appList) intents[++i] = uninstallIntent(ri.activityInfo.packageName, pm);
return intents;
}
}
31 changes: 28 additions & 3 deletions app/src/main/java/net/emilla/utils/Dialogs.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,28 @@ public static TimePickerDialog timePicker(final Context ctxt, @StringRes final i
return timePicker;
}

public static AlertDialog.Builder withIntents(final AlertDialog.Builder builder, final AssistActivity act, final CharSequence[] labels, final Intent[] intents) {
public static AlertDialog.Builder withIntents(final AlertDialog.Builder builder,
final AssistActivity act, final CharSequence[] labels, final Intent[] intents) {
return builder.setItems(labels, (dialog, which) -> act.succeed(intents[which]));
}

private static AlertDialog.Builder withApps(final AlertDialog.Builder builder, final AssistActivity act, final PackageManager pm, final List<ResolveInfo> appList) {
public static AlertDialog.Builder withNullableIntents(final AlertDialog.Builder builder,
final AssistActivity act, final CharSequence[] labels, final Intent[] intents,
final CharSequence failMsg) {
return builder.setItems(labels, (dialog, which) -> {
final Intent in = intents[which];
if (in == null) act.fail(failMsg);
else act.succeed(in);
});
}

private static AlertDialog.Builder withApps(final AlertDialog.Builder builder,
final AssistActivity act, final PackageManager pm, final List<ResolveInfo> appList) {
return withIntents(builder, act, Apps.labels(appList, pm), Apps.intents(appList));
}

public static AlertDialog.Builder appChooser(final AssistActivity act, final PackageManager pm, final List<ResolveInfo> appList) {
public static AlertDialog.Builder appChooser(final AssistActivity act, final PackageManager pm,
final List<ResolveInfo> appList) {
// TODO: due to duplicate app labels, it's important to eventually include app icons in this dialog
// TODO: allow for alpha sort. important for screen readers (it should be on by default in that case)
// only reason not to is i kind of like the random order. makes my phone feel less cramped.
Expand All @@ -100,4 +113,16 @@ public static AlertDialog.Builder appChooser(final AssistActivity act, final Pac
final AlertDialog.Builder base = base(act, R.string.dialog_app);
return withApps(base, act, pm, appList);
}

private static AlertDialog.Builder withUninstalls(final AlertDialog.Builder builder,
final AssistActivity act, final PackageManager pm, final List<ResolveInfo> appList) {
return withNullableIntents(builder, act, Apps.labels(appList, pm), Apps.uninstalls(appList, pm),
"No settings app found for your device"); // Todo: instead handle at mapping somehow
}

public static AlertDialog.Builder appUninstaller(final AssistActivity act,
final List<ResolveInfo> appList) {
final AlertDialog.Builder base = base(act, R.string.dialog_app);
return withUninstalls(base, act, act.getPackageManager(), appList);
}
}
3 changes: 1 addition & 2 deletions app/src/main/java/net/emilla/utils/Permissions.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;

Expand Down Expand Up @@ -37,7 +36,7 @@ private static AlertDialog courtesyDialog(final AssistActivity act, final String
private static AlertDialog permissionDialog(final AssistActivity act, final PackageManager pm,
@StringRes final int permId) {
final Intent settings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:" + act.getPackageName()));
Apps.pkgUri(act.getPackageName()));
final boolean noAppInfo = settings.resolveActivity(pm) == null;
if (noAppInfo) settings.setAction(Settings.ACTION_SETTINGS).setData(null)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/res/drawable/ic_uninstall.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="@color/icons"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>
6 changes: 6 additions & 0 deletions app/src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<item>@string/command_settings</item>
<item>@string/command_share</item>
<item>@string/command_info</item>
<item>@string/command_uninstall</item>
<item>@string/command_toast</item>
<!-- <item>@string/command_todo</item>-->
<item>@string/command_pomodoro</item>
Expand Down Expand Up @@ -97,6 +98,7 @@
<item>settings</item>
<item>share</item>
<item>info</item>
<item>uninstall</item>
<item>toast</item>
<!-- <item>todo</item>-->
<item>pomodoro</item>
Expand Down Expand Up @@ -176,6 +178,10 @@
<item>mrk</item>
</string-array>
<string-array name="aliases_info" />
<string-array name="aliases_uninstall">
<item>remove</item>
<item>delete</item>
</string-array>
<string-array name="aliases_toast" />

<!-- App aliases -->
Expand Down
Loading

0 comments on commit 493f47e

Please sign in to comment.