From cda119a8842300ef851608992f23f29070dca7a2 Mon Sep 17 00:00:00 2001 From: Muntashir Al-Islam Date: Wed, 12 Jul 2023 22:31:19 +0600 Subject: [PATCH] [AppInfo] Add a new tag: Bloatware Clicking on the tag opens a dialog containing description, dependencies, alternatives, etc. like in the Debloater page Signed-off-by: Muntashir Al-Islam --- .../AppManager/StaticDataset.java | 75 +++++++++++++ .../debloat/BloatwareDetailsDialog.java | 36 +++++- .../AppManager/debloat/DebloatObject.java | 66 ++++++++--- .../debloat/DebloaterViewModel.java | 106 +----------------- .../AppManager/debloat/SuggestionObject.java | 2 +- .../details/info/AppInfoFragment.java | 8 ++ .../details/info/AppInfoViewModel.java | 10 ++ .../utils/appearance/ColorCodes.java | 4 + 8 files changed, 184 insertions(+), 123 deletions(-) diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/StaticDataset.java b/app/src/main/java/io/github/muntashirakon/AppManager/StaticDataset.java index bd6c52528b1..c614f3fb3e5 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/StaticDataset.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/StaticDataset.java @@ -2,23 +2,37 @@ package io.github.muntashirakon.AppManager; +import android.content.Context; import android.content.res.Resources; import android.util.DisplayMetrics; +import androidx.annotation.NonNull; +import androidx.annotation.WorkerThread; import androidx.collection.ArrayMap; import androidx.core.os.ConfigurationCompat; import androidx.core.os.LocaleListCompat; +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; +import io.github.muntashirakon.AppManager.db.utils.AppDb; +import io.github.muntashirakon.AppManager.debloat.DebloatObject; +import io.github.muntashirakon.AppManager.debloat.SuggestionObject; import io.github.muntashirakon.AppManager.misc.VMRuntime; import io.github.muntashirakon.AppManager.utils.ContextUtils; +import io.github.muntashirakon.AppManager.utils.FileUtils; public class StaticDataset { private static String[] sTrackerCodeSignatures; private static String[] sTrackerNames; + private static List sDebloatObjects; public static final String ARMEABI_V7A = "armeabi_v7a"; public static final String ARM64_V8A = "arm64_v8a"; @@ -81,4 +95,65 @@ public static String[] getTrackerNames() { } return sTrackerNames; } + + @WorkerThread + public static List getDebloatObjects() { + if (sDebloatObjects == null) { + sDebloatObjects = loadDebloatObjects(ContextUtils.getContext(), new Gson()); + } + return sDebloatObjects; + } + + @WorkerThread + public static List getDebloatObjectsWithInstalledInfo(@NonNull Context context) { + AppDb appDb = new AppDb(); + if (sDebloatObjects == null) { + sDebloatObjects = loadDebloatObjects(context, new Gson()); + } + for (DebloatObject debloatObject : sDebloatObjects) { + debloatObject.fillInstallInfo(context, appDb); + } + return sDebloatObjects; + } + + @NonNull + @WorkerThread + private static List loadDebloatObjects(@NonNull Context context, @NonNull Gson gson) { + HashMap> idSuggestionObjectsMap = loadSuggestions(context, gson); + String jsonContent = FileUtils.getContentFromAssets(context, "debloat.json"); + try { + List debloatObjects = Arrays.asList(gson.fromJson(jsonContent, DebloatObject[].class)); + for (DebloatObject debloatObject : debloatObjects) { + List suggestionObjects = idSuggestionObjectsMap.get(debloatObject.getSuggestionId()); + debloatObject.setSuggestions(suggestionObjects); + } + return debloatObjects; + } catch (Throwable e) { + e.printStackTrace(); + return Collections.emptyList(); + } + } + + @NonNull + @WorkerThread + private static HashMap> loadSuggestions(@NonNull Context context, @NonNull Gson gson) { + String jsonContent = FileUtils.getContentFromAssets(context, "suggestions.json"); + HashMap> idSuggestionObjectsMap = new HashMap<>(); + try { + SuggestionObject[] suggestionObjects = gson.fromJson(jsonContent, SuggestionObject[].class); + if (suggestionObjects != null) { + for (SuggestionObject suggestionObject : suggestionObjects) { + List objects = idSuggestionObjectsMap.get(suggestionObject.suggestionId); + if (objects == null) { + objects = new ArrayList<>(); + idSuggestionObjectsMap.put(suggestionObject.suggestionId, objects); + } + objects.add(suggestionObject); + } + } + } catch (Throwable th) { + th.printStackTrace(); + } + return idSuggestionObjectsMap; + } } diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/debloat/BloatwareDetailsDialog.java b/app/src/main/java/io/github/muntashirakon/AppManager/debloat/BloatwareDetailsDialog.java index 3bf3c94bcb8..e45b67e7ae0 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/debloat/BloatwareDetailsDialog.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/debloat/BloatwareDetailsDialog.java @@ -2,6 +2,7 @@ package io.github.muntashirakon.AppManager.debloat; +import android.app.Application; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -17,6 +18,8 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.widget.LinearLayoutCompat; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; @@ -30,7 +33,10 @@ import java.util.List; import io.github.muntashirakon.AppManager.R; +import io.github.muntashirakon.AppManager.StaticDataset; +import io.github.muntashirakon.AppManager.db.utils.AppDb; import io.github.muntashirakon.AppManager.details.AppDetailsActivity; +import io.github.muntashirakon.AppManager.utils.ThreadUtils; import io.github.muntashirakon.AppManager.utils.UIUtils; import io.github.muntashirakon.AppManager.utils.appearance.ColorCodes; import io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment; @@ -80,7 +86,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat dismiss(); return; } - DebloaterViewModel viewModel = new ViewModelProvider(requireActivity()).get(DebloaterViewModel.class); + BloatwareDetailsViewModel viewModel = new ViewModelProvider(requireActivity()).get(BloatwareDetailsViewModel.class); mAppIconView = view.findViewById(R.id.icon); mOpenAppInfoButton = view.findViewById(R.id.info); mAppLabelView = view.findViewById(R.id.name); @@ -94,7 +100,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat mAdapter = new SuggestionsAdapter(); mSuggestionView.setAdapter(mAdapter); - viewModel.getDebloatObjectLiveData().observe(getViewLifecycleOwner(), debloatObject -> { + viewModel.debloatObjectLiveData.observe(getViewLifecycleOwner(), debloatObject -> { if (debloatObject == null) { dismiss(); return; @@ -110,6 +116,7 @@ private void updateDialog(@NonNull DebloatObject debloatObject) { mAppIconView.setImageDrawable(icon != null ? icon : requireActivity().getPackageManager().getDefaultActivityIcon()); int[] users = debloatObject.getUsers(); if (users != null && users.length > 0) { + mOpenAppInfoButton.setVisibility(View.VISIBLE); mOpenAppInfoButton.setOnClickListener(v -> { Intent appDetailsIntent = AppDetailsActivity.getIntent(requireContext(), debloatObject.packageName, users[0]); @@ -124,10 +131,11 @@ private void updateDialog(@NonNull DebloatObject debloatObject) { mPackageNameView.setText(debloatObject.packageName); String warning = debloatObject.getWarning(); if (warning != null) { + mWarningView.setVisibility(View.VISIBLE); mWarningView.setText(warning); if (debloatObject.getRemoval() != DebloatObject.REMOVAL_CAUTION) { mWarningView.setAlertType(MaterialAlertView.ALERT_TYPE_INFO); - } + } else mWarningView.setAlertType(MaterialAlertView.ALERT_TYPE_WARN); } else mWarningView.setVisibility(View.GONE); mDescriptionView.setText(getDescription(debloatObject)); // Add tags @@ -212,6 +220,28 @@ private void addTag(@NonNull ViewGroup parent, @NonNull CharSequence title) { parent.addView(chip); } + public static class BloatwareDetailsViewModel extends AndroidViewModel { + public final MutableLiveData debloatObjectLiveData = new MutableLiveData<>(); + + public BloatwareDetailsViewModel(@NonNull Application application) { + super(application); + } + + public void findDebloatObject(@NonNull String packageName) { + ThreadUtils.postOnBackgroundThread(() -> { + List debloatObjects = StaticDataset.getDebloatObjects(); + for (DebloatObject debloatObject : debloatObjects) { + if (packageName.equals(debloatObject.packageName)) { + debloatObject.fillInstallInfo(getApplication(), new AppDb()); + debloatObjectLiveData.postValue(debloatObject); + return; + } + } + debloatObjectLiveData.postValue(null); + }); + } + } + private class SuggestionsAdapter extends RecyclerView.Adapter { private final List mSuggestions = Collections.synchronizedList(new ArrayList<>()); diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloatObject.java b/app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloatObject.java index 1a4d7c0ad32..4d6a15ea371 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloatObject.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloatObject.java @@ -2,7 +2,14 @@ package io.github.muntashirakon.AppManager.debloat; +import static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES; +import static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; +import android.os.RemoteException; import androidx.annotation.IntDef; import androidx.annotation.NonNull; @@ -14,6 +21,10 @@ import java.lang.annotation.RetentionPolicy; import java.util.List; +import io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat; +import io.github.muntashirakon.AppManager.compat.PackageManagerCompat; +import io.github.muntashirakon.AppManager.db.entity.App; +import io.github.muntashirakon.AppManager.db.utils.AppDb; import io.github.muntashirakon.AppManager.utils.ArrayUtils; public class DebloatObject { @@ -61,6 +72,7 @@ public class DebloatObject { private Drawable mIcon; @Nullable private CharSequence mLabel; + @Nullable private int[] mUsers; private boolean mInstalled; @Nullable @@ -124,24 +136,17 @@ public CharSequence getLabel() { return mLabel != null ? mLabel : mInternalLabel; } - public void setLabel(@Nullable CharSequence label) { - mLabel = label; - } - @Nullable public Drawable getIcon() { return mIcon; } - public void setIcon(@Nullable Drawable icon) { - mIcon = icon; - } - + @Nullable public int[] getUsers() { return mUsers; } - public void addUser(int userId) { + private void addUser(int userId) { if (mUsers == null) { mUsers = new int[]{userId}; } else { @@ -153,10 +158,6 @@ public boolean isInstalled() { return mInstalled; } - public void setInstalled(boolean installed) { - mInstalled = installed; - } - public boolean isSystemApp() { return Boolean.TRUE.equals(mSystemApp); } @@ -165,7 +166,42 @@ public boolean isUserApp() { return Boolean.FALSE.equals(mSystemApp); } - public void setSystemApp(@Nullable Boolean systemApp) { - mSystemApp = systemApp; + public void fillInstallInfo(@NonNull Context context, @NonNull AppDb appDb) { + PackageManager pm = context.getPackageManager(); + List suggestionObjects = getSuggestions(); + if (suggestionObjects != null) { + for (SuggestionObject suggestionObject : suggestionObjects) { + List apps = appDb.getAllApplications(suggestionObject.packageName); + for (App app : apps) { + if (app.isInstalled) { + suggestionObject.addUser(app.userId); + } + } + } + } + // Update application data + mInstalled = false; + mUsers = null; + List apps = appDb.getAllApplications(packageName); + for (App app : apps) { + if (!app.isInstalled) { + continue; + } + mInstalled = true; + addUser(app.userId); + mSystemApp = app.isSystemApp(); + mLabel = app.packageLabel; + if (getIcon() == null) { + try { + ApplicationInfo ai = PackageManagerCompat.getApplicationInfo(packageName, + MATCH_UNINSTALLED_PACKAGES | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, app.userId); + mInstalled = (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0; + mSystemApp = ApplicationInfoCompat.isSystemApp(ai); + mLabel = ai.loadLabel(pm); + mIcon = ai.loadIcon(pm); + } catch (RemoteException | PackageManager.NameNotFoundException ignore) { + } + } + } } } diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterViewModel.java b/app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterViewModel.java index 1b5f7993baf..f426efb67f7 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterViewModel.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterViewModel.java @@ -2,13 +2,7 @@ package io.github.muntashirakon.AppManager.debloat; -import static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES; -import static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES; - import android.app.Application; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.RemoteException; import android.os.UserHandleHidden; import android.text.TextUtils; @@ -19,8 +13,6 @@ import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import com.google.gson.Gson; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -30,16 +22,12 @@ import java.util.Map; import java.util.concurrent.ExecutorService; -import io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat; -import io.github.muntashirakon.AppManager.compat.PackageManagerCompat; -import io.github.muntashirakon.AppManager.db.entity.App; -import io.github.muntashirakon.AppManager.db.utils.AppDb; +import io.github.muntashirakon.AppManager.StaticDataset; import io.github.muntashirakon.AppManager.misc.AdvancedSearchView; import io.github.muntashirakon.AppManager.types.UserPackagePair; import io.github.muntashirakon.AppManager.users.Users; import io.github.muntashirakon.AppManager.utils.AppPref; import io.github.muntashirakon.AppManager.utils.ArrayUtils; -import io.github.muntashirakon.AppManager.utils.FileUtils; import io.github.muntashirakon.AppManager.utils.MultithreadedExecutor; public class DebloaterViewModel extends AndroidViewModel { @@ -50,14 +38,10 @@ public class DebloaterViewModel extends AndroidViewModel { private int mQueryType; @NonNull private final List mDebloatObjects = new ArrayList<>(); - @NonNull - private final HashMap> mIdSuggestionObjectsMap = new HashMap<>(); private final Map mSelectedPackages = new HashMap<>(); private final MutableLiveData> mDebloatObjectListLiveData = new MutableLiveData<>(); - private final MutableLiveData mDebloatObjectLiveData = new MutableLiveData<>(); private final ExecutorService mExecutor = MultithreadedExecutor.getNewInstance(); - private final Gson mGson = new Gson(); public DebloaterViewModel(@NonNull Application application) { super(application); @@ -90,10 +74,6 @@ public LiveData> getDebloatObjectListLiveData() { return mDebloatObjectListLiveData; } - public LiveData getDebloatObjectLiveData() { - return mDebloatObjectLiveData; - } - public int getTotalItemCount() { return mDebloatObjects.size(); } @@ -142,19 +122,6 @@ public ArrayList getSelectedPackagesWithUsers() { return userPackagePairs; } - public void findDebloatObject(@NonNull String packageName) { - mExecutor.submit(() -> { - for (DebloatObject object : mDebloatObjects) { - if (packageName.equals(object.packageName)) { - mDebloatObjectLiveData.postValue(object); - return; - } - } - mDebloatObjectLiveData.postValue(null); - - }); - } - @AnyThread public void loadPackages() { mExecutor.submit(() -> { @@ -232,75 +199,6 @@ private void loadDebloatObjects() { if (!mDebloatObjects.isEmpty()) { return; } - loadSuggestions(); - String jsonContent = FileUtils.getContentFromAssets(getApplication(), "debloat.json"); - try { - mDebloatObjects.addAll(Arrays.asList(mGson.fromJson(jsonContent, DebloatObject[].class))); - } catch (Throwable e) { - e.printStackTrace(); - } - if (mDebloatObjects.isEmpty()) { - return; - } - PackageManager pm = getApplication().getPackageManager(); - // Fetch package info for all users - AppDb appDb = new AppDb(); - for (DebloatObject debloatObject : mDebloatObjects) { - // Update suggestion data - List suggestionObjects = mIdSuggestionObjectsMap.get(debloatObject.getSuggestionId()); - debloatObject.setSuggestions(suggestionObjects); - // Update application data - List apps = appDb.getAllApplications(debloatObject.packageName); - for (App app : apps) { - if (!app.isInstalled) { - continue; - } - debloatObject.setInstalled(true); - debloatObject.addUser(app.userId); - debloatObject.setSystemApp(app.isSystemApp()); - debloatObject.setLabel(app.packageLabel); - if (debloatObject.getIcon() == null) { - try { - ApplicationInfo ai = PackageManagerCompat.getApplicationInfo(debloatObject.packageName, - MATCH_UNINSTALLED_PACKAGES | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, app.userId); - debloatObject.setInstalled((ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0); - debloatObject.setSystemApp(ApplicationInfoCompat.isSystemApp(ai)); - debloatObject.setLabel(ai.loadLabel(pm)); - debloatObject.setIcon(ai.loadIcon(pm)); - } catch (RemoteException | PackageManager.NameNotFoundException ignore) { - } - } - } - } - } - - @WorkerThread - private void loadSuggestions() { - if (!mIdSuggestionObjectsMap.isEmpty()) { - return; - } - String jsonContent = FileUtils.getContentFromAssets(getApplication(), "suggestions.json"); - try { - SuggestionObject[] suggestionObjects = mGson.fromJson(jsonContent, SuggestionObject[].class); - if (suggestionObjects != null) { - AppDb appDb = new AppDb(); - for (SuggestionObject suggestionObject : suggestionObjects) { - List objects = mIdSuggestionObjectsMap.get(suggestionObject.suggestionId); - if (objects == null) { - objects = new ArrayList<>(); - mIdSuggestionObjectsMap.put(suggestionObject.suggestionId, objects); - } - objects.add(suggestionObject); - List apps = appDb.getAllApplications(suggestionObject.packageName); - for (App app : apps) { - if (app.isInstalled) { - suggestionObject.addUser(app.userId); - } - } - } - } - } catch (Throwable th) { - th.printStackTrace(); - } + mDebloatObjects.addAll(StaticDataset.getDebloatObjectsWithInstalledInfo(getApplication())); } } diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/debloat/SuggestionObject.java b/app/src/main/java/io/github/muntashirakon/AppManager/debloat/SuggestionObject.java index 265c027122f..5ec9b991af5 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/debloat/SuggestionObject.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/debloat/SuggestionObject.java @@ -63,7 +63,7 @@ public int[] getUsers() { public void addUser(int userId) { if (mUsers == null) { mUsers = new int[]{userId}; - } else { + } else if (!ArrayUtils.contains(mUsers, userId)) { mUsers = ArrayUtils.appendInt(mUsers, userId); } } diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoFragment.java b/app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoFragment.java index b2a166c518e..dc400672477 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoFragment.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoFragment.java @@ -108,6 +108,7 @@ import io.github.muntashirakon.AppManager.compat.ManifestCompat; import io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat; import io.github.muntashirakon.AppManager.compat.PackageManagerCompat; +import io.github.muntashirakon.AppManager.debloat.BloatwareDetailsDialog; import io.github.muntashirakon.AppManager.details.AppDetailsActivity; import io.github.muntashirakon.AppManager.details.AppDetailsFragment; import io.github.muntashirakon.AppManager.details.AppDetailsViewModel; @@ -827,6 +828,13 @@ private void setupTagCloud(AppInfoViewModel.TagCloud tagCloud) { .setNegativeButton(R.string.close, null) .show()); } + if (tagCloud.isBloatware) { + addChip("Bloatware", ColorCodes.getBloatwareIndicatorColor(mActivity)) + .setOnClickListener(v -> { + BloatwareDetailsDialog dialog = BloatwareDetailsDialog.getInstance(mPackageName); + dialog.show(getChildFragmentManager(), BloatwareDetailsDialog.TAG); + }); + } if (tagCloud.hasKeyStoreItems) { Chip chip; if (tagCloud.hasMasterKeyInKeyStore) { diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoViewModel.java b/app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoViewModel.java index bc6f5b4eab0..86831221caa 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoViewModel.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoViewModel.java @@ -33,6 +33,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import io.github.muntashirakon.AppManager.StaticDataset; import io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat; import io.github.muntashirakon.AppManager.apk.installer.PackageInstallerService; import io.github.muntashirakon.AppManager.backup.BackupUtils; @@ -44,6 +45,7 @@ import io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat; 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.details.AppDetailsViewModel; import io.github.muntashirakon.AppManager.magisk.MagiskDenyList; import io.github.muntashirakon.AppManager.magisk.MagiskHide; @@ -186,6 +188,13 @@ public void loadTagCloud() { } } tagCloud.isMagiskDenyListEnabled = !isExternalApk && magiskDenyListEnabled; + List debloatObjects = StaticDataset.getDebloatObjects(); + for (DebloatObject debloatObject : debloatObjects) { + if (packageName.equals(debloatObject.packageName)) { + tagCloud.isBloatware = true; + break; + } + } tagCloud.canWriteAndExecute = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q; tagCloud.hasKeyStoreItems = KeyStoreUtils.hasKeyStore(applicationInfo.uid); @@ -379,6 +388,7 @@ public static class TagCloud { public boolean isAppSuspended; public boolean isMagiskHideEnabled; public boolean isMagiskDenyListEnabled; + public boolean isBloatware; public boolean canWriteAndExecute; public boolean hasKeyStoreItems; public boolean hasMasterKeyInKeyStore; diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/utils/appearance/ColorCodes.java b/app/src/main/java/io/github/muntashirakon/AppManager/utils/appearance/ColorCodes.java index de42ce0102b..b9b74d2144a 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/utils/appearance/ColorCodes.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/utils/appearance/ColorCodes.java @@ -75,6 +75,10 @@ public static int getAppWriteAndExecuteIndicatorColor(@NonNull Context context) return ContextCompat.getColor(context, R.color.red); } + public static int getBloatwareIndicatorColor(@NonNull Context context) { + return ContextCompat.getColor(context, R.color.tracker); + } + public static int getAppSuspendedIndicatorColor(@NonNull Context context) { return ContextCompat.getColor(context, R.color.stopped); }