Skip to content

Commit

Permalink
[Finder] Add new filters: app_type, compile_sdk, shared_uid
Browse files Browse the repository at this point in the history
1. shared_uid filter retrieve apps
   - with shared user ID
   - without shared user ID
   - with matching shared user ID name(s), including regular expressions
2. compile_sdk filter retrieve apps with the given SDK value(s)
3. app_type filter retrieves apps when one or more of the generic
   conditions below are or aren't satisfied:
   - user apps
   - system apps
   - updated system apps
   - privileged apps
   - data-only apps
   - force-stopped apps
   - apps requesting large heap
   - debuggable apps
   - test-only apps
   - apps with code (DEX/SO files)
   - persistent apps
   - apps allowing framework-provided backups (e.g., ADB backups)
   - apps installed in the external storage (or in the internal storage)
   - apps using cleartext-only (HTTP) traffic
   - apps having an SSAID

Signed-off-by: Muntashir Al-Islam <[email protected]>
  • Loading branch information
MuntashirAkon committed Nov 21, 2024
1 parent f5b6216 commit 83832c9
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandleHidden;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand Down Expand Up @@ -43,6 +44,7 @@
import io.github.muntashirakon.AppManager.compat.PackageManagerCompat;
import io.github.muntashirakon.AppManager.db.entity.Backup;
import io.github.muntashirakon.AppManager.debloat.DebloatObject;
import io.github.muntashirakon.AppManager.filters.options.AppTypeOption;
import io.github.muntashirakon.AppManager.filters.options.ComponentsOption;
import io.github.muntashirakon.AppManager.filters.options.FreezeOption;
import io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;
Expand Down Expand Up @@ -81,6 +83,8 @@ public class FilterableAppInfo {
private PackageSizeInfo mPackageSizeInfo;
private AppUsageStatsManager.DataUsage mDataUsage;
private DebloatObject mBloatwareInfo;
private Integer mFreezeFlags = null;
private Integer mAppTypeFlags = null;

public FilterableAppInfo(@NonNull PackageInfo packageInfo, @Nullable PackageUsageInfo packageUsageInfo) {
mPackageInfo = packageInfo;
Expand Down Expand Up @@ -264,17 +268,20 @@ public boolean isFrozen() {
}

public int getFreezeFlags() {
int flags = 0;
if (mFreezeFlags != null) {
return mFreezeFlags;
}
mFreezeFlags = 0;
if (!isEnabled()) {
flags |= FreezeOption.FREEZE_TYPE_DISABLED;
mFreezeFlags |= FreezeOption.FREEZE_TYPE_DISABLED;
}
if (isHidden()) {
flags |= FreezeOption.FREEZE_TYPE_HIDDEN;
mFreezeFlags |= FreezeOption.FREEZE_TYPE_HIDDEN;
}
if (isSuspended()) {
flags |= FreezeOption.FREEZE_TYPE_SUSPENDED;
mFreezeFlags |= FreezeOption.FREEZE_TYPE_SUSPENDED;
}
return flags;
return mFreezeFlags;
}

public boolean isStopped() {
Expand All @@ -289,6 +296,60 @@ public boolean isDebuggable() {
return (mApplicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}

public int getAppTypeFlags() {
if (mAppTypeFlags != null) {
return mAppTypeFlags;
}
mAppTypeFlags = 0;
if (isSystemApp()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_SYSTEM;
} else {
mAppTypeFlags |= AppTypeOption.APP_TYPE_USER;
}
if (isUpdatedSystemApp()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_UPDATED_SYSTEM;
}
if (isPrivileged()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_PRIVILEGED;
}
if (dataOnlyApp()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_DATA_ONLY;
}
if (isStopped()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_STOPPED;
}
if (requestedLargeHeap()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_LARGE_HEAP;
}
if (isDebuggable()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_DEBUGGABLE;
}
if (isTestOnly()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_TEST_ONLY;
}
if (hasCode()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_HAS_CODE;
}
if (isPersistent()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_PERSISTENT;
}
if (backupAllowed()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_ALLOW_BACKUP;
}
if (installedInExternalStorage()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_INSTALLED_IN_EXTERNAL;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (usesHttp()) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_HTTP_ONLY;
}
}
if (!TextUtils.isEmpty(getSsaid())) {
mAppTypeFlags |= AppTypeOption.APP_TYPE_SSAID;
}
return mAppTypeFlags;
}

public boolean isSystemApp() {
return ApplicationInfoCompat.isSystemApp(mApplicationInfo);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-3.0-or-later

package io.github.muntashirakon.AppManager.filters.options;

import android.os.Build;

import androidx.annotation.NonNull;

import java.util.LinkedHashMap;
import java.util.Map;

import io.github.muntashirakon.AppManager.filters.FilterableAppInfo;

public class AppTypeOption extends FilterOption {
public static final int APP_TYPE_USER = 1 << 0;
public static final int APP_TYPE_SYSTEM = 1 << 1;
public static final int APP_TYPE_UPDATED_SYSTEM = 1 << 2;
public static final int APP_TYPE_PRIVILEGED = 1 << 3;
public static final int APP_TYPE_DATA_ONLY = 1 << 4;
public static final int APP_TYPE_STOPPED = 1 << 5;
public static final int APP_TYPE_SENSORS = 1 << 6;
public static final int APP_TYPE_LARGE_HEAP = 1 << 7;
public static final int APP_TYPE_DEBUGGABLE = 1 << 8;
public static final int APP_TYPE_TEST_ONLY = 1 << 9;
public static final int APP_TYPE_HAS_CODE = 1 << 10;
public static final int APP_TYPE_PERSISTENT = 1 << 11;
public static final int APP_TYPE_ALLOW_BACKUP = 1 << 12;
public static final int APP_TYPE_INSTALLED_IN_EXTERNAL = 1 << 13;
public static final int APP_TYPE_HTTP_ONLY = 1 << 14;
public static final int APP_TYPE_BATTERY_OPT_ENABLED = 1 << 15;
public static final int APP_TYPE_PLAY_APP_SIGNING = 1 << 16;
public static final int APP_TYPE_SSAID = 1 << 17;
public static final int APP_TYPE_KEYSTORE = 1 << 18;
public static final int APP_TYPE_WITH_RULES = 1 << 19;
public static final int APP_TYPE_PWA = 1 << 20;
public static final int APP_TYPE_SHORT_CODE = 1 << 21;
public static final int APP_TYPE_OVERLAY = 1 << 22;

private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{
put(KEY_ALL, TYPE_NONE);
put("with_flags", TYPE_INT_FLAGS);
put("without_flags", TYPE_INT_FLAGS);
}};

private final Map<Integer, CharSequence> mFrozenFlags = new LinkedHashMap<Integer, CharSequence>() {{
put(APP_TYPE_USER, "User App");
put(APP_TYPE_SYSTEM, "System App");
put(APP_TYPE_UPDATED_SYSTEM, "Updated System App");
put(APP_TYPE_PRIVILEGED, "Privileged App");
put(APP_TYPE_DATA_ONLY, "Data-only App");
put(APP_TYPE_STOPPED, "Force-stopped App");
// put(APP_TYPE_SENSORS, "Uses Sensors"); // TODO: 11/21/24 (dynamic)
put(APP_TYPE_LARGE_HEAP, "Requests Large Heap");
put(APP_TYPE_DEBUGGABLE, "Debuggable App");
put(APP_TYPE_TEST_ONLY, "Test-only App");
put(APP_TYPE_HAS_CODE, "Has Code");
put(APP_TYPE_PERSISTENT, "Persistent App");
put(APP_TYPE_ALLOW_BACKUP, "Backup Allowed");
put(APP_TYPE_INSTALLED_IN_EXTERNAL, "Installed in External Storage");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
put(APP_TYPE_HTTP_ONLY, "Uses Cleartext (HTTP) Traffic");
}
// put(APP_TYPE_BATTERY_OPT_ENABLED, "Battery Optimized"); // TODO: 11/21/24 (dynamic)
// put(APP_TYPE_PLAY_APP_SIGNING, "Uses Play App Signing"); // TODO: 11/21/24
put(APP_TYPE_SSAID, "Has SSAID");
// put(APP_TYPE_KEYSTORE, "Uses Android KeyStore"); // TODO: 11/21/24
// put(APP_TYPE_WITH_RULES, "Has Rules"); // TODO: 11/21/24
// put(APP_TYPE_PWA, "Progressive Web App (PWA)"); // TODO: 11/21/24
// put(APP_TYPE_SHORT_CODE, "Uses Short Code"); // TODO: 11/21/24
// put(APP_TYPE_OVERLAY, "Overlay App"); // TODO: 11/21/24
}};

public AppTypeOption() {
super("app_type");
}

@NonNull
@Override
public Map<String, Integer> getKeysWithType() {
return mKeysWithType;
}

@Override
public Map<Integer, CharSequence> getFlags(@NonNull String key) {
if (key.equals("with_flags") || key.equals("without_flags")) {
return mFrozenFlags;
}
return super.getFlags(key);
}

@NonNull
@Override
public TestResult test(@NonNull FilterableAppInfo info, @NonNull TestResult result) {
int appTypeFlags = info.getAppTypeFlags();
switch (key) {
default:
return result.setMatched(true);
case "with_flags": {
return result.setMatched((appTypeFlags & intValue) == intValue);
}
case "without_flags": {
return result.setMatched((appTypeFlags & intValue) != intValue);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: GPL-3.0-or-later

package io.github.muntashirakon.AppManager.filters.options;

import android.os.Build;

import androidx.annotation.NonNull;

import java.util.LinkedHashMap;
import java.util.Map;

import io.github.muntashirakon.AppManager.filters.FilterableAppInfo;

public class CompileSdkOption extends FilterOption {
private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{
put(KEY_ALL, TYPE_NONE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
put("eq", TYPE_INT);
put("le", TYPE_INT);
put("ge", TYPE_INT);
}
}};

public CompileSdkOption() {
super("compile_sdk");
}

@NonNull
@Override
public Map<String, Integer> getKeysWithType() {
return mKeysWithType;
}

@NonNull
@Override
public TestResult test(@NonNull FilterableAppInfo info, @NonNull TestResult result) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
return result.setMatched(true);
}
switch (key) {
default:
return result.setMatched(true);
case "eq":
return result.setMatched(info.getCompileSdk() == intValue);
case "le":
return result.setMatched(info.getCompileSdk() <= intValue);
case "ge":
return result.setMatched(info.getCompileSdk() >= intValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ public static FilterOption create(@NonNull String filterName) {
switch (filterName) {
case "apk_size": return new ApkSizeOption();
case "app_label": return new AppLabelOption();
case "app_type": return new AppTypeOption();
case "backup": return new BackupOption();
case "bloatware": return new BloatwareOption();
case "cache_size": return new CacheSizeOption();
case "compile_sdk": return new CompileSdkOption();
case "components": return new ComponentsOption();
case "data_size": return new DataSizeOption();
case "data_usage": return new DataUsageOption();
Expand All @@ -25,6 +27,7 @@ public static FilterOption create(@NonNull String filterName) {
case "pkg_name": return new PackageNameOption();
case "running_apps": return new RunningAppsOption();
case "screen_time": return new ScreenTimeOption();
case "shared_uid": return new SharedUidOption();
case "signature": return new SignatureOption();
case "target_sdk": return new TargetSdkOption();
case "times_opened": return new TimesOpenedOption();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public Map<String, Integer> getKeysWithType() {
public TestResult test(@NonNull FilterableAppInfo info, @NonNull TestResult result) {
InstallSourceInfoCompat installSourceInfo = info.getInstallerInfo();
if (installSourceInfo == null) {
return result.setMatched(key.equals("all"));
return result.setMatched(key.equals(KEY_ALL));
}
// There's at least one installer at this point
Set<String> installers = getInstallers(installSourceInfo);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-3.0-or-later

package io.github.muntashirakon.AppManager.filters.options;

import androidx.annotation.NonNull;

import java.util.LinkedHashMap;
import java.util.Map;

import io.github.muntashirakon.AppManager.filters.FilterableAppInfo;
import io.github.muntashirakon.AppManager.utils.ArrayUtils;

public class SharedUidOption extends FilterOption {
private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{
put(KEY_ALL, TYPE_NONE);
put("with_shared", TYPE_NONE);
put("without_shared", TYPE_NONE);
put("uid_name", TYPE_STR_SINGLE);
put("uid_names", TYPE_STR_MULTIPLE);
put("uid_name_regex", TYPE_REGEX);
}};

public SharedUidOption() {
super("shared_uid");
}

@NonNull
@Override
public Map<String, Integer> getKeysWithType() {
return mKeysWithType;
}

@NonNull
@Override
public TestResult test(@NonNull FilterableAppInfo info, @NonNull TestResult result) {
String shared_uid = info.getSharedUserId();
switch (key) {
default:
return result.setMatched(false);
case "with_shared":
return result.setMatched(shared_uid != null);
case "without_shared":
return result.setMatched(shared_uid == null);
case "uid_name":
return result.setMatched(shared_uid.equals(value));
case "installers":
return result.setMatched(ArrayUtils.contains(stringValues, shared_uid));
case "regex":
return result.setMatched(regexValue.matcher(shared_uid).matches());
}
}
}
3 changes: 3 additions & 0 deletions app/src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,11 @@
<string-array name="finder_filters">
<item>apk_size</item>
<item>app_label</item>
<item>app_type</item>
<item>backup</item>
<item>bloatware</item>
<item>cache_size</item>
<item>compile_sdk</item>
<item>components</item>
<item>data_size</item>
<item>data_usage</item>
Expand All @@ -258,6 +260,7 @@
<item>pkg_name</item>
<item>running_apps</item>
<item>screen_time</item>
<item>shared_uid</item>
<item>signature</item>
<item>target_sdk</item>
<item>times_opened</item>
Expand Down

0 comments on commit 83832c9

Please sign in to comment.