...
 
Commits (44)
......@@ -5,22 +5,23 @@ Yet another android package manager and viewer but...
- It is free and open source
- It has material design (and a nice UI)
- It doesn't have any useless permissions
- It doesn't connect to the internet
- It doesn't connect to the internet (internet permission is required for ADB mode)
- It tries to display as much information as possible in the main window
- It lists activities, broadcast receivers, services, providers, permissions, signatures, shared libraries, etc. of any app
- It can launch (exportable) activities, create (customizable) shortcuts
- It can block any activities, broadcast receivers, services or providers you like with Watt and Blocker import support (requires root)
- It can revoke permissions that are considered dangerous (requires root)
- It can disable app ops that are considered dangerous (requires root)
- It can revoke permissions that are considered dangerous (requires root/ADB)
- It can disable app ops that are considered dangerous (requires root/ADB)
- It can scan for trackers in apps and list (all or only) tracking classes (and their code dump)
- It can generate dynamic manifest for any app
- It can be used to view/edit/delete shared preferences of any app (requires root)
- It displays running processes/apps (requires root)
- It displays running processes/apps (requires root/ADB)
- It displays your app usage, data usage and app storage info (requires “Usage Access” permission)
- Apk files can be shared (hence the use of a provider)
- It can be used to clear app data or app cache (requires root)
- It can be used to clear app data or app cache (requires root/ADB)
- Batch operations: clear app data, disable run in background, disable/kill/uninstall apps
...and other minor features such as uninstalling/enabling/disabling apps, displaying app installation info, opening on F-Droid or Aurora Droid.
...and other minor features such as uninstalling/enabling/disabling apps, displaying app installation info, opening on F-Droid, Aurora Droid or Aurora Store.
It basically combined the features of five or six apps that any tech-savy person is needed to install in order to have a “life”.
......
......@@ -54,4 +54,5 @@ dependencies {
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'com.jaredrummler:android-shell:1.0.0'
implementation 'com.tananaev:adblib:1.2'
}
......@@ -3,8 +3,10 @@
xmlns:tools="http://schemas.android.com/tools"
package="io.github.muntashirakon.AppManager"
android:installLocation="auto">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"
android:maxSdkVersion="25" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
......@@ -13,6 +15,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:name=".AppManager"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme">
<activity
......
package io.github.muntashirakon.AppManager;
import android.app.Application;
import android.content.Context;
public class AppManager extends Application {
private static AppManager instance;
public static AppManager getInstance() {
return instance;
}
public static Context getContext(){
return instance;
}
@Override
public void onCreate() {
instance = this;
super.onCreate();
}
}
......@@ -58,8 +58,9 @@ public class MainLoader extends AsyncTaskLoader<List<ApplicationItem>> {
item.size = (long) -1 * applicationInfo.targetSdkVersion;
}
if (isRootEnabled) {
item.blockedCount = ComponentsBlocker.getInstance(getContext(), pName, true)
.componentCount();
try (ComponentsBlocker cb = ComponentsBlocker.getInstance(getContext(), pName, true)) {
item.blockedCount = cb.componentCount();
}
}
itemList.add(item);
} catch (PackageManager.NameNotFoundException ignored) {}
......@@ -86,8 +87,9 @@ public class MainLoader extends AsyncTaskLoader<List<ApplicationItem>> {
item.sha = new Tuple<>("?", "?");
}
if (isRootEnabled) {
item.blockedCount = ComponentsBlocker.getInstance(getContext(),
applicationInfo.packageName, true).componentCount();
try (ComponentsBlocker cb = ComponentsBlocker.getInstance(getContext(), applicationInfo.packageName, true)) {
item.blockedCount = cb.componentCount();
}
}
itemList.add(item);
}
......
......@@ -25,12 +25,12 @@ import android.view.View;
import android.webkit.MimeTypeMap;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.progressindicator.ProgressIndicator;
import com.google.classysharkandroid.utils.IOUtils;
import java.io.File;
......@@ -95,7 +95,7 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
private SwipeRefreshLayout mSwipeRefresh;
private int mAccentColor;
private CharSequence mPackageLabel;
private ProgressBar mProgressBar;
private ProgressIndicator mProgressIndicator;
@Override
protected void onCreate(Bundle savedInstanceState) {
......@@ -116,7 +116,7 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
mHorizontalLayout = findViewById(R.id.horizontal_layout);
mTagCloud = findViewById(R.id.tag_cloud);
mAccentColor = Utils.getThemeColor(this, android.R.attr.colorAccent);
mProgressBar = findViewById(R.id.progress_horizontal);
mProgressIndicator = findViewById(R.id.progress_linear);
}
@Override
......@@ -250,21 +250,22 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
// Set uninstall
addToHorizontalLayout(R.string.uninstall, R.drawable.ic_delete_black_24dp).setOnClickListener(v -> {
final boolean isSystemApp = (mApplicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
final Boolean isRootEnabled = (Boolean) AppPref.get(this, AppPref.PREF_ROOT_MODE_ENABLED, AppPref.TYPE_BOOLEAN);
if (isRootEnabled) {
if (AppPref.isRootEnabled()) {
new AlertDialog.Builder(this, R.style.CustomDialog)
.setTitle(mPackageLabel)
.setMessage(isSystemApp ?
R.string.uninstall_system_app_message : R.string.uninstall_app_message)
.setPositiveButton(R.string.uninstall, (dialog, which) -> {
.setPositiveButton(R.string.uninstall, (dialog, which) -> new Thread(() -> {
// Try without root first then with root
if (Runner.run(this, String.format("pm uninstall --user 0 %s", mPackageName)).isSuccessful()) {
Toast.makeText(mActivity, String.format(getString(R.string.uninstalled_successfully), mPackageLabel), Toast.LENGTH_LONG).show();
finish();
runOnUiThread(() -> {
Toast.makeText(mActivity, String.format(getString(R.string.uninstalled_successfully), mPackageLabel), Toast.LENGTH_LONG).show();
finish();
});
} else {
Toast.makeText(mActivity, String.format(getString(R.string.failed_to_uninstall), mPackageLabel), Toast.LENGTH_LONG).show();
runOnUiThread(() -> Toast.makeText(mActivity, String.format(getString(R.string.failed_to_uninstall), mPackageLabel), Toast.LENGTH_LONG).show());
}
})
}).start())
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
if (dialog != null) dialog.cancel();
})
......@@ -276,38 +277,38 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
}
});
// Enable/disable app (root only)
if ((Boolean) AppPref.get(this, AppPref.PREF_ROOT_MODE_ENABLED, AppPref.TYPE_BOOLEAN)) {
if (AppPref.isRootEnabled() || AppPref.isAdbEnabled()) {
if (mApplicationInfo.enabled) {
// Disable app
addToHorizontalLayout(R.string.disable, R.drawable.ic_block_black_24dp).setOnClickListener(v -> {
addToHorizontalLayout(R.string.disable, R.drawable.ic_block_black_24dp).setOnClickListener(v -> new Thread(() -> {
if (Runner.run(this, String.format("pm disable %s", mPackageName)).isSuccessful()) {
// Refresh
getPackageInfoOrFinish();
runOnUiThread(this::getPackageInfoOrFinish);
} else {
Toast.makeText(mActivity, String.format(getString(R.string.failed_to_disable), mPackageLabel), Toast.LENGTH_LONG).show();
runOnUiThread(() -> Toast.makeText(mActivity, String.format(getString(R.string.failed_to_disable), mPackageLabel), Toast.LENGTH_LONG).show());
}
});
}).start());
} else {
// Enable app
addToHorizontalLayout(R.string.enable, R.drawable.ic_baseline_get_app_24).setOnClickListener(v -> {
addToHorizontalLayout(R.string.enable, R.drawable.ic_baseline_get_app_24).setOnClickListener(v -> new Thread(() -> {
if (Runner.run(this, String.format("pm enable %s", mPackageName)).isSuccessful()) {
// Refresh
getPackageInfoOrFinish();
runOnUiThread(this::getPackageInfoOrFinish);
} else {
Toast.makeText(mActivity, String.format(getString(R.string.failed_to_enable), mPackageLabel), Toast.LENGTH_LONG).show();
runOnUiThread(() -> Toast.makeText(mActivity, String.format(getString(R.string.failed_to_enable), mPackageLabel), Toast.LENGTH_LONG).show());
}
});
}).start());
}
// Force stop
if ((mApplicationInfo.flags & ApplicationInfo.FLAG_STOPPED) == 0) {
addToHorizontalLayout(R.string.force_stop, R.drawable.ic_baseline_power_settings_new_24).setOnClickListener(v -> {
addToHorizontalLayout(R.string.force_stop, R.drawable.ic_baseline_power_settings_new_24).setOnClickListener(v -> new Thread(() -> {
if (Runner.run(this, String.format("am force-stop %s", mPackageName)).isSuccessful()) {
// Refresh
getPackageInfoOrFinish();
runOnUiThread(this::getPackageInfoOrFinish);
} else {
Toast.makeText(mActivity, String.format(getString(R.string.failed_to_stop), mPackageLabel), Toast.LENGTH_LONG).show();
runOnUiThread(() -> Toast.makeText(mActivity, String.format(getString(R.string.failed_to_stop), mPackageLabel), Toast.LENGTH_LONG).show());
}
});
}).start());
}
} // End root only
// Set manifest
......@@ -330,7 +331,7 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
}
});
// Root only features
if ((Boolean) AppPref.get(this, AppPref.PREF_ROOT_MODE_ENABLED, AppPref.TYPE_BOOLEAN)) {
if (AppPref.isRootEnabled()) {
// Shared prefs (root only)
List<String> sharedPrefs;
sharedPrefs = getSharedPrefs(mApplicationInfo.dataDir);
......@@ -375,28 +376,28 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
} // End root only features
// Set F-Droid or Aurora Droid
try {
if(!mPackageManager.getApplicationInfo(PACKAGE_NAME_FDROID, 0).enabled)
if(!mPackageManager.getApplicationInfo(PACKAGE_NAME_AURORA_DROID, 0).enabled)
throw new PackageManager.NameNotFoundException();
addToHorizontalLayout(R.string.fdroid, R.drawable.ic_frost_fdroid_black_24dp)
addToHorizontalLayout(R.string.aurora, R.drawable.ic_frost_auroradroid_black_24dp)
.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClassName(PACKAGE_NAME_FDROID, ACTIVITY_NAME_FDROID);
intent.setClassName(PACKAGE_NAME_AURORA_DROID, ACTIVITY_NAME_AURORA_DROID);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("appid", mPackageName);
intent.putExtra("INTENT_PACKAGE_NAME", mPackageName);
try {
startActivity(intent);
} catch (Exception ignored) {}
});
} catch (PackageManager.NameNotFoundException e) {
try {
if(!mPackageManager.getApplicationInfo(PACKAGE_NAME_AURORA_DROID, 0).enabled)
if(!mPackageManager.getApplicationInfo(PACKAGE_NAME_FDROID, 0).enabled)
throw new PackageManager.NameNotFoundException();
addToHorizontalLayout(R.string.aurora, R.drawable.ic_frost_auroradroid_black_24dp)
addToHorizontalLayout(R.string.fdroid, R.drawable.ic_frost_fdroid_black_24dp)
.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClassName(PACKAGE_NAME_AURORA_DROID, ACTIVITY_NAME_AURORA_DROID);
intent.setClassName(PACKAGE_NAME_FDROID, ACTIVITY_NAME_FDROID);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("INTENT_PACKAGE_NAME", mPackageName);
intent.putExtra("appid", mPackageName);
try {
startActivity(intent);
} catch (Exception ignored) {}
......@@ -645,7 +646,6 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
}
private void setStorageInfo(long codeSize, long dataSize, long cacheSize, long obbSize, long mediaSize) {
final Boolean isRootEnabled = (Boolean) AppPref.get(this, AppPref.PREF_ROOT_MODE_ENABLED, AppPref.TYPE_BOOLEAN);
mList.addItemWithTitle(getString(R.string.storage_and_cache), true);
mList.item_title.setTextColor(mAccentColor);
// Code size
......@@ -654,20 +654,20 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
// Data size
mList.addItemWithTitleSubtitle(getString(R.string.data_size), getReadableSize(dataSize),
ListItemCreator.SELECTABLE);
if (isRootEnabled) {
mList.setOpen(v -> {
if (AppPref.isRootEnabled() || AppPref.isAdbEnabled()) {
mList.setOpen(v -> new Thread(() -> {
// Clear data
if (Runner.run(this, String.format("pm clear %s", mPackageName)).isSuccessful()) {
getPackageInfoOrFinish();
runOnUiThread(this::getPackageInfoOrFinish);
}
});
}).start());
mList.item_open.setImageDrawable(getDrawable(R.drawable.ic_delete_black_24dp));
}
// Cache size
mList.addItemWithTitleSubtitle(getString(R.string.cache_size), getReadableSize(cacheSize),
ListItemCreator.SELECTABLE);
if (isRootEnabled) {
mList.setOpen(v -> {
if (AppPref.isRootEnabled() || AppPref.isAdbEnabled()) {
mList.setOpen(v -> new Thread(() -> {
StringBuilder command = new StringBuilder(String.format("rm -rf %s/cache %s/code_cache",
mApplicationInfo.dataDir, mApplicationInfo.dataDir));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
......@@ -682,9 +682,9 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
command.append(" ").append(extCache);
}
if (Runner.run(this, command.toString()).isSuccessful()) {
getPackageInfoOrFinish();
runOnUiThread(this::getPackageInfoOrFinish);
}
});
}).start());
mList.item_open.setImageDrawable(getDrawable(R.drawable.ic_delete_black_24dp));
}
// OBB size
......@@ -704,7 +704,7 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
* Get package info.
*/
private void getPackageInfoOrFinish() {
mProgressBar.setVisibility(View.VISIBLE);
mProgressIndicator.show();
new Thread(() -> {
try {
final int signingCertFlag;
......@@ -737,7 +737,7 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
runOnUiThread(this::setHeaderView);
runOnUiThread(this::setHorizontalView);
runOnUiThread(this::setVerticalView);
runOnUiThread(() -> mProgressBar.setVisibility(View.GONE));
runOnUiThread(() -> mProgressIndicator.hide());
} catch (PackageManager.NameNotFoundException e) {
runOnUiThread(this::finish);
}
......@@ -756,7 +756,7 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
/**
* Get network stats.
* TODO: Doesn't work in newer Android versions
*
* @param uid Application UID
* @return A tuple consisting of transmitted and received data
*/
......@@ -768,9 +768,9 @@ public class AppInfoActivity extends AppCompatActivity implements SwipeRefreshLa
if (uidStatsDir.exists() && uidStatsDir.isDirectory()) {
for (File child : Objects.requireNonNull(uidStatsDir.listFiles())) {
if (child.getName().equals(UID_STATS_TR))
tuple.setFirst(getReadableSize(Long.parseLong(Utils.getFileContent(child))));
tuple.setFirst(getReadableSize(Long.parseLong(Utils.getFileContent(child, "-1"))));
else if (child.getName().equals(UID_STATS_RC))
tuple.setSecond(getReadableSize(Long.parseLong(Utils.getFileContent(child))));
tuple.setSecond(getReadableSize(Long.parseLong(Utils.getFileContent(child, "-1"))));
}
}
return tuple;
......
......@@ -12,7 +12,6 @@ import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.text.format.Formatter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
......@@ -27,6 +26,9 @@ import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
import com.google.android.material.progressindicator.ProgressIndicator;
import com.google.android.material.textview.MaterialTextView;
import java.lang.ref.WeakReference;
import java.text.Collator;
import java.text.DateFormat;
......@@ -42,10 +44,12 @@ import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.menu.MenuBuilder;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.fragments.AppUsageDetailsDialogFragment;
import io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;
import io.github.muntashirakon.AppManager.usage.Utils.IntervalType;
import io.github.muntashirakon.AppManager.utils.Tuple;
import io.github.muntashirakon.AppManager.utils.Utils;
import static io.github.muntashirakon.AppManager.usage.Utils.USAGE_LAST_BOOT;
......@@ -53,7 +57,7 @@ import static io.github.muntashirakon.AppManager.usage.Utils.USAGE_TODAY;
import static io.github.muntashirakon.AppManager.usage.Utils.USAGE_WEEKLY;
import static io.github.muntashirakon.AppManager.usage.Utils.USAGE_YESTERDAY;
public class AppUsageActivity extends AppCompatActivity implements ListView.OnItemClickListener {
public class AppUsageActivity extends AppCompatActivity implements ListView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener {
@IntDef(value = {
SORT_BY_APP_LABEL,
SORT_BY_LAST_USED,
......@@ -75,9 +79,11 @@ public class AppUsageActivity extends AppCompatActivity implements ListView.OnIt
R.id.action_sort_by_mobile_data, R.id.action_sort_by_package_name,
R.id.action_sort_by_screen_time, R.id.action_sort_by_times_opened};
private ProgressIndicator mProgressIndicator;
private SwipeRefreshLayout mSwipeRefresh;
private AppUsageAdapter mAppUsageAdapter;
List<AppUsageStatsManager.PackageUS> mPackageUSList;
private long totalScreenTime;
private static long totalScreenTime;
private @IntervalType int current_interval = USAGE_TODAY;
private @SortOrder int mSortBy;
......@@ -92,6 +98,8 @@ public class AppUsageActivity extends AppCompatActivity implements ListView.OnIt
actionBar.setTitle(getString(R.string.app_usage));
}
mProgressIndicator = findViewById(R.id.progress_linear);
// Get usage stats
mAppUsageAdapter = new AppUsageAdapter(this);
ListView listView = findViewById(android.R.id.list);
......@@ -100,6 +108,12 @@ public class AppUsageActivity extends AppCompatActivity implements ListView.OnIt
listView.setAdapter(mAppUsageAdapter);
listView.setOnItemClickListener(this);
mSwipeRefresh = findViewById(R.id.swipe_refresh);
mSwipeRefresh.setColorSchemeColors(Utils.getThemeColor(this, android.R.attr.colorAccent));
mSwipeRefresh.setProgressBackgroundColorSchemeColor(Utils.getThemeColor(this, android.R.attr.colorPrimary));
mSwipeRefresh.setOnRefreshListener(this);
mSwipeRefresh.setOnChildScrollUpCallback((parent, child) -> listView.canScrollVertically(-1));
@SuppressLint("InflateParams")
View header = getLayoutInflater().inflate(R.layout.header_app_usage, null);
listView.addHeaderView(header);
......@@ -130,6 +144,14 @@ public class AppUsageActivity extends AppCompatActivity implements ListView.OnIt
else getAppUsage();
}
@Override
public void onRefresh() {
mSwipeRefresh.setRefreshing(false);
// Check permission
if (!Utils.checkUsageStatsPermission(this)) promptForUsageStatsPermission();
else getAppUsage();
}
@SuppressLint("RestrictedApi")
@Override
public boolean onCreateOptionsMenu(Menu menu) {
......@@ -223,15 +245,22 @@ public class AppUsageActivity extends AppCompatActivity implements ListView.OnIt
}
private void getAppUsage() {
int _try = 5; // try to get usage stat 5 times
do {
mPackageUSList = AppUsageStatsManager.getInstance(this).getUsageStats(0, current_interval);
} while (0 != --_try && mPackageUSList.size() == 0);
mAppUsageAdapter.setDefaultList(mPackageUSList);
totalScreenTime = 0;
for(AppUsageStatsManager.PackageUS appItem: mPackageUSList) totalScreenTime += appItem.screenTime;
sortPackageUSList();
setUsageSummary();
mProgressIndicator.show();
new Thread(() -> {
int _try = 5; // try to get usage stat 5 times
do {
mPackageUSList = AppUsageStatsManager.getInstance(this).getUsageStats(0, current_interval);
} while (0 != --_try && mPackageUSList.size() == 0);
totalScreenTime = 0;
for (AppUsageStatsManager.PackageUS appItem : mPackageUSList)
totalScreenTime += appItem.screenTime;
sortPackageUSList();
runOnUiThread(() -> {
mAppUsageAdapter.setDefaultList(mPackageUSList);
setUsageSummary();
mProgressIndicator.hide();
});
}).start();
}
private void promptForUsageStatsPermission() {
......@@ -304,12 +333,14 @@ public class AppUsageActivity extends AppCompatActivity implements ListView.OnIt
static class ViewHolder {
ImageView appIcon;
TextView appLabel;
TextView packageName;
TextView lastUsageDate;
TextView mobileDataUsage;
TextView wifiDataUsage;
TextView screenTime;
MaterialTextView appLabel;
MaterialTextView packageName;
MaterialTextView lastUsageDate;
MaterialTextView mobileDataUsage;
MaterialTextView wifiDataUsage;
MaterialTextView screenTime;
MaterialTextView percentUsage;
ProgressIndicator usageIndicator;
IconAsyncTask iconLoader;
}
......@@ -353,12 +384,15 @@ public class AppUsageActivity extends AppCompatActivity implements ListView.OnIt
holder.mobileDataUsage = convertView.findViewById(R.id.data_usage);
holder.wifiDataUsage = convertView.findViewById(R.id.wifi_usage);
holder.screenTime = convertView.findViewById(R.id.screen_time);
holder.percentUsage = convertView.findViewById(R.id.percent_usage);
holder.usageIndicator = convertView.findViewById(R.id.progress_linear);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
if(holder.iconLoader != null) holder.iconLoader.cancel(true);
}
AppUsageStatsManager.PackageUS packageUS = mAdapterList.get(position);
final AppUsageStatsManager.PackageUS packageUS = mAdapterList.get(position);
final int percentUsage = (int) (packageUS.screenTime * 100f / totalScreenTime);
// Set label (or package name on failure)
try {
ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageUS.packageName, 0);
......@@ -387,11 +421,21 @@ public class AppUsageActivity extends AppCompatActivity implements ListView.OnIt
holder.screenTime.setText(screenTimesWithTimesOpened);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Set data usage
holder.mobileDataUsage.setText("M: \u2191 " + Formatter.formatFileSize(mActivity, packageUS.mobileData.getFirst())
+ " \u2193 " + Formatter.formatFileSize(mActivity, packageUS.mobileData.getSecond()));
holder.wifiDataUsage.setText("W: \u2191 " + Formatter.formatFileSize(mActivity, packageUS.wifiData.getFirst())
+ " \u2193 " + Formatter.formatFileSize(mActivity, packageUS.wifiData.getSecond()));
final Tuple<Long, Long> mobileData = packageUS.mobileData;
if (mobileData.getFirst() != 0 || mobileData.getSecond() != 0) {
holder.mobileDataUsage.setText("M: \u2191 " + Formatter.formatFileSize(mActivity, mobileData.getFirst())
+ " \u2193 " + Formatter.formatFileSize(mActivity, mobileData.getSecond()));
} else holder.mobileDataUsage.setText("");
final Tuple<Long, Long> wifiData = packageUS.wifiData;
if (wifiData.getFirst() != 0 || wifiData.getSecond() != 0) {
holder.wifiDataUsage.setText("W: \u2191 " + Formatter.formatFileSize(mActivity, wifiData.getFirst())
+ " \u2193 " + Formatter.formatFileSize(mActivity, wifiData.getSecond()));
} else holder.wifiDataUsage.setText("");
}
// Set usage percentage
holder.percentUsage.setText(String.format(Locale.ROOT, "%d%%", percentUsage));
holder.usageIndicator.setProgress(percentUsage);
return convertView;
}
......
......@@ -3,7 +3,6 @@ package io.github.muntashirakon.AppManager.activities;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
......@@ -23,10 +22,10 @@ import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.progressindicator.ProgressIndicator;
import com.google.classysharkandroid.dex.DexLoaderBuilder;
import com.google.classysharkandroid.reflector.ClassesNamesList;
import com.google.classysharkandroid.reflector.Reflector;
......@@ -82,7 +81,7 @@ public class ClassListingActivity extends AppCompatActivity implements SearchVie
private String packageInfo = "";
private CharSequence mAppName;
private ActionBar mActionBar;
private ProgressBar mProgressBar;
private ProgressIndicator mProgressIndicator;
private static String mConstraint;
private String mPackageName;
......@@ -159,7 +158,7 @@ public class ClassListingActivity extends AppCompatActivity implements SearchVie
mListView.setDividerHeight(0);
mListView.setEmptyView(findViewById(android.R.id.empty));
mProgressBar = findViewById(R.id.progress_horizontal);
mProgressIndicator = findViewById(R.id.progress_linear);
final Uri uriFromIntent = inIntent.getData();
classList = new ClassesNamesList();
......@@ -315,7 +314,7 @@ public class ClassListingActivity extends AppCompatActivity implements SearchVie
.setView(showText)
.setIcon(R.drawable.ic_frost_classysharkexodus_black_24dp)
.setNegativeButton(android.R.string.ok, null)
.setNeutralButton(R.string.exodus_link, (DialogInterface.OnClickListener) (dialog, which) -> {
.setNeutralButton(R.string.exodus_link, (dialog, which) -> {
Uri exodus_link = Uri.parse(String.format("https://reports.exodus-privacy.eu.org/en/reports/%s/latest/", mPackageName));
Intent intent = new Intent(Intent.ACTION_VIEW, exodus_link);
if (intent.resolveActivity(getPackageManager()) != null) {
......@@ -396,7 +395,7 @@ public class ClassListingActivity extends AppCompatActivity implements SearchVie
}
// mListView.setAdapter(mAdapter);
mListView.setAdapter(mClassListingAdapter);
mProgressBar.setVisibility(View.GONE);
mProgressIndicator.hide();
if (classList.getClassNames().isEmpty() && totalClassesScanned == 0) {
// FIXME: Add support for odex (using root)
Toast.makeText(ClassListingActivity.this, R.string.system_odex_not_supported, Toast.LENGTH_LONG).show();
......
......@@ -11,10 +11,10 @@ import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.google.android.material.progressindicator.ProgressIndicator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
......@@ -62,7 +62,7 @@ public class ClassViewerActivity extends AppCompatActivity {
("\\b[A-Z][A-Za-z0-9_]+\\b", Pattern.MULTILINE);
private String classDump;
private ProgressBar mProgressBar;
private ProgressIndicator mProgressIndicator;
@Override
protected void onCreate(Bundle savedInstanceState) {
......@@ -72,7 +72,7 @@ public class ClassViewerActivity extends AppCompatActivity {
else
setContentView(R.layout.activity_any_viewer);
mProgressBar = findViewById(R.id.progress_horizontal);
mProgressIndicator = findViewById(R.id.progress_linear);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
......@@ -91,7 +91,7 @@ public class ClassViewerActivity extends AppCompatActivity {
}
private void displayContent() {
showProgressBar(true);
mProgressIndicator.show();
final TextView textView = findViewById(R.id.any_view);
final int typeClassColor = ContextCompat.getColor(this, R.color.ocean_blue);
final int keywordsColor = ContextCompat.getColor(this, R.color.dark_orange);
......@@ -120,15 +120,11 @@ public class ClassViewerActivity extends AppCompatActivity {
}
runOnUiThread(() -> {
textView.setText(spannableString);
ClassViewerActivity.this.showProgressBar(false);
mProgressIndicator.hide();
});
}).start();
}
private void showProgressBar(boolean show) {
mProgressBar.setVisibility(show ? View.VISIBLE : View.GONE);
}
@SuppressLint("RestrictedApi")
@Override
public boolean onCreateOptionsMenu(Menu menu) {
......
......@@ -25,22 +25,25 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.SectionIndexer;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.bottomappbar.BottomAppBar;
import com.google.android.material.progressindicator.ProgressIndicator;
import com.google.android.material.textview.MaterialTextView;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.text.Collator;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
......@@ -56,6 +59,7 @@ import java.util.concurrent.TimeUnit;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
......@@ -69,6 +73,8 @@ import androidx.loader.content.Loader;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import io.github.muntashirakon.AppManager.MainLoader;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.adb.AdbShell;
import io.github.muntashirakon.AppManager.batchops.BatchOpsManager;
import io.github.muntashirakon.AppManager.types.ApplicationItem;
import io.github.muntashirakon.AppManager.utils.AppPref;
import io.github.muntashirakon.AppManager.utils.Utils;
......@@ -126,7 +132,7 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
private List<ApplicationItem> mItemList = new ArrayList<>();
private int mItemSizeRetrievedCount;
private ListView mListView;
private ProgressBar mProgressBar;
private ProgressIndicator mProgressIndicator;
private LoaderManager mLoaderManager;
private SwipeRefreshLayout mSwipeRefresh;
private BottomAppBar mBottomAppBar;
......@@ -139,6 +145,7 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
private MenuItem appUsageMenu;
private MenuItem runningAppsMenu;
private MenuItem sortByBlockedComponentMenu;
private BatchOpsManager mBatchOpsManager;
private @SortOrder int mSortBy;
@SuppressLint("RestrictedApi")
......@@ -170,7 +177,7 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
listName = getIntent().getStringExtra(EXTRA_LIST_NAME);
if (listName == null) listName = "Onboard.packages";
mProgressBar = findViewById(R.id.progress_horizontal);
mProgressIndicator = findViewById(R.id.progress_linear);
mListView = findViewById(R.id.item_list);
mSwipeRefresh = findViewById(R.id.swipe_refresh);
mBottomAppBar = findViewById(R.id.bottom_appbar);
......@@ -204,6 +211,7 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
return true;
});
mBatchOpsManager = new BatchOpsManager(this);
Menu menu = mBottomAppBar.getMenu();
if (menu instanceof MenuBuilder) {
......@@ -217,31 +225,37 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
});
mBottomAppBar.setOnMenuItemClickListener(item -> {
switch (item.getItemId()) {
case R.id.action_uninstall:
case R.id.action_disable:
case R.id.action_clear_data:
case R.id.action_backup_apk:
handleBatchOp(BatchOpsManager.OP_CLEAR_DATA, R.string.alert_failed_to_clear_data);
return true;
case R.id.action_disable:
handleBatchOp(BatchOpsManager.OP_DISABLE, R.string.alert_failed_to_disable);
return true;
case R.id.action_disable_background:
handleBatchOp(BatchOpsManager.OP_DISABLE_BACKGROUND, R.string.alert_failed_to_disable_background);
return true;
case R.id.action_kill_process:
handleBatchOp(BatchOpsManager.OP_KILL, R.string.alert_failed_to_kill);
return true;
case R.id.action_uninstall:
handleBatchOp(BatchOpsManager.OP_UNINSTALL, R.string.alert_failed_to_uninstall);
return true;
case R.id.action_backup_apk:
case R.id.action_backup_data:
case R.id.action_disable_background:
case R.id.action_export_blocking_data:
Toast.makeText(this, "This operation is not supported yet.", Toast.LENGTH_LONG).show();
mPackageNames.clear();
mListView.invalidateViews();
handleSelection();
return true;
}
mPackageNames.clear();
mListView.invalidateViews();
handleSelection();
return false;
});
handleSelection();
// Initialize app prefs
AppPref.getInstance(this);
// Check root
if (!Utils.isRootGiven(this))
AppPref.getInstance(this).setPref(AppPref.PREF_ROOT_MODE_ENABLED, false);
mLoaderManager = LoaderManager.getInstance(this);
mLoaderManager.initLoader(0, null, this);
}
......@@ -262,11 +276,11 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
} else appUsageMenu.setVisible(false);
runningAppsMenu = menu.findItem(R.id.action_running_apps);
sortByBlockedComponentMenu = menu.findItem(R.id.action_sort_by_blocked_components);
if ((Boolean) AppPref.get(this, AppPref.PREF_ROOT_MODE_ENABLED, AppPref.TYPE_BOOLEAN)) {
if (AppPref.isRootEnabled() || AppPref.isAdbEnabled()) {
runningAppsMenu.setVisible(true);
sortByBlockedComponentMenu.setVisible(true);
} else {
runningAppsMenu.setVisible(true);
runningAppsMenu.setVisible(false);
sortByBlockedComponentMenu.setVisible(false);
}
MenuItem apkUpdaterMenu = menu.findItem(R.id.action_apk_updater);
......@@ -378,7 +392,7 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
@NonNull
@Override
public Loader<List<ApplicationItem>> onCreateLoader(int id, @Nullable Bundle args) {
showProgressBar(true);
showProgressIndicator(true);
return new MainLoader(this);
}
......@@ -398,14 +412,14 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
if (Build.VERSION.SDK_INT <= 25) {
startRetrievingPackagesSize();
}
showProgressBar(false);
showProgressIndicator(false);
}
@Override
public void onLoaderReset(@NonNull Loader<List<ApplicationItem>> loader) {
mItemList = null;
mAdapter.setDefaultList(null);
showProgressBar(false);
showProgressIndicator(false);
}
@Override
......@@ -431,6 +445,19 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
@Override
protected void onResume() {
super.onResume();
// Check root
if (!Utils.isRootGiven(this)) {
AppPref.getInstance(this).setPref(AppPref.PREF_ROOT_MODE_ENABLED, false);
// Check for adb
new Thread(() -> {
try {
AdbShell.run("id");
AppPref.getInstance(this).setPref(AppPref.PREF_ADB_MODE_ENABLED, true);
} catch (IOException | InterruptedException | NoSuchAlgorithmException e) {
AppPref.getInstance(this).setPref(AppPref.PREF_ADB_MODE_ENABLED, false);
}
}).start();
} else AppPref.getInstance(this).setPref(AppPref.PREF_ADB_MODE_ENABLED, false);
// Set filter
if (mAdapter != null && mConstraint != null && !mConstraint.equals("")) {
mAdapter.getFilter().filter(mConstraint);
......@@ -443,7 +470,7 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
}
// Set sort by
mSortBy = (int) AppPref.get(this, AppPref.PREF_MAIN_WINDOW_SORT_ORDER, AppPref.TYPE_INTEGER);
if ((Boolean) AppPref.get(this, AppPref.PREF_ROOT_MODE_ENABLED, AppPref.TYPE_BOOLEAN)) {
if (AppPref.isRootEnabled() || AppPref.isAdbEnabled()) {
if (runningAppsMenu != null) runningAppsMenu.setVisible(true);
if (sortByBlockedComponentMenu != null) sortByBlockedComponentMenu.setVisible(true);
} else {
......@@ -464,8 +491,32 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
}
}
private void showProgressBar(boolean show) {
mProgressBar.setVisibility(show ? View.VISIBLE : View.GONE);
private void handleBatchOp(@BatchOpsManager.OpType int op, @StringRes int msg) {
showProgressIndicator(true);
new Thread(() -> {
if (!mBatchOpsManager.performOp(op, new ArrayList<>(mPackageNames)).isSuccessful()) {
runOnUiThread(() -> new AlertDialog.Builder(this, R.style.CustomDialog)
.setTitle(msg)
.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
mBatchOpsManager.getLastResult().failedPackages()), null)
.setNegativeButton(android.R.string.ok, null)
.show());
} else {
runOnUiThread(() -> Toast.makeText(this,
R.string.the_operation_was_successful, Toast.LENGTH_LONG).show());
}
mPackageNames.clear();
runOnUiThread(() -> {
mListView.invalidateViews();
handleSelection();
showProgressIndicator(false);
});
}).start();
}
private void showProgressIndicator(boolean show) {
if (show) mProgressIndicator.show();
else mProgressIndicator.hide();
}
/**
......@@ -716,18 +767,16 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
holder.iconLoader.cancel(true);
}
ApplicationItem item = mAdapterList.get(i);
ApplicationInfo info = item.applicationInfo;
final ApplicationItem item = mAdapterList.get(i);
final ApplicationInfo info = item.applicationInfo;
// Alternate background colors
if (mPackageNames.contains(info.packageName)) {
if (mPackageNames.contains(info.packageName))
view.setBackgroundColor(mColorHighlight);
} else view.setBackgroundColor(i % 2 == 0 ? mColorSemiTransparent : mColorTransparent);
// If the app is disabled, add an ocean blue background
if (!info.enabled) {
else if (!info.enabled)
view.setBackgroundColor(ContextCompat.getColor(mActivity, R.color.disabled_app));
}
else view.setBackgroundColor(i % 2 == 0 ? mColorSemiTransparent : mColorTransparent);
// Add yellow star if the app is in debug mode
holder.favorite_icon.setVisibility(item.star ? View.VISIBLE : View.INVISIBLE);
try {
......@@ -837,7 +886,10 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
holder.icon.setOnClickListener(v -> {
if (MainActivity.mPackageNames.contains(info.packageName)) {
MainActivity.mPackageNames.remove(info.packageName);
finalView.setBackgroundColor(i % 2 == 0 ? mColorSemiTransparent : mColorTransparent);
if (!info.enabled)
finalView.setBackgroundColor(ContextCompat.getColor(mActivity, R.color.disabled_app));
else
finalView.setBackgroundColor(i % 2 == 0 ? mColorSemiTransparent : mColorTransparent);
} else {
MainActivity.mPackageNames.add(info.packageName);
finalView.setBackgroundColor(mColorHighlight);
......
......@@ -11,11 +11,11 @@ import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.progressindicator.ProgressIndicator;
import java.lang.ref.WeakReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
......@@ -45,7 +45,7 @@ public class ManifestViewerActivity extends AppCompatActivity {
Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
private static String code;
private ProgressBar mProgressBar;
private ProgressIndicator mProgressIndicator;
@Override
......@@ -57,7 +57,7 @@ public class ManifestViewerActivity extends AppCompatActivity {
setContentView(R.layout.activity_any_viewer);
setSupportActionBar(findViewById(R.id.toolbar));
mProgressBar = findViewById(R.id.progress_horizontal);
mProgressIndicator = findViewById(R.id.progress_linear);
String packageName = getIntent().getStringExtra(EXTRA_PACKAGE_NAME);
String filePath = null, applicationLabel = null;
......@@ -120,7 +120,7 @@ public class ManifestViewerActivity extends AppCompatActivity {
}
runOnUiThread(() -> {
textView.setText(spannableString);
ManifestViewerActivity.this.showProgressBar(false);
ManifestViewerActivity.this.showProgressIndicator(false);
});
}).start();
}
......@@ -130,8 +130,9 @@ public class ManifestViewerActivity extends AppCompatActivity {
finish();
}
private void showProgressBar(boolean show) {
mProgressBar.setVisibility(show ? View.VISIBLE : View.GONE);
private void showProgressIndicator(boolean show) {
if (show) mProgressIndicator.show();
else mProgressIndicator.hide();
}
/**
......@@ -150,7 +151,7 @@ public class ManifestViewerActivity extends AppCompatActivity {
@Override
protected void onPreExecute() {
super.onPreExecute();
if(mActivity.get() != null) mActivity.get().showProgressBar(true);
if(mActivity.get() != null) mActivity.get().showProgressIndicator(true);
}
@Override
......@@ -189,7 +190,7 @@ public class ManifestViewerActivity extends AppCompatActivity {
// @Override
// protected void onPreExecute() {
// super.onPreExecute();
// if (mActivity.get() != null) mActivity.get().showProgressBar(true);
// if (mActivity.get() != null) mActivity.get().showProgressIndicator(true);
// }
//
// @Override
......@@ -223,7 +224,7 @@ public class ManifestViewerActivity extends AppCompatActivity {
// protected void onPostExecute(Boolean result) {
// super.onPostExecute(result);
// if (mActivity.get() != null) {
// mActivity.get().showProgressBar(false);
// mActivity.get().showProgressIndicator(false);
// if (result)
// mActivity.get().displayContent();
// else
......
package io.github.muntashirakon.AppManager.activities;
import android.annotation.SuppressLint;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
......@@ -9,6 +10,7 @@ import android.os.Bundle;
import android.text.format.Formatter;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
......@@ -17,11 +19,11 @@ import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.progressindicator.ProgressIndicator;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
......@@ -35,13 +37,15 @@ import java.util.regex.Pattern;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.menu.MenuBuilder;
import androidx.appcompat.widget.SearchView;
import androidx.core.content.ContextCompat;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.appops.AppOpsManager;
import io.github.muntashirakon.AppManager.appops.AppOpsService;
import io.github.muntashirakon.AppManager.compontents.ComponentsBlocker;
import io.github.muntashirakon.AppManager.runner.Runner;
import io.github.muntashirakon.AppManager.storage.StorageManager;
import io.github.muntashirakon.AppManager.utils.AppPref;
import io.github.muntashirakon.AppManager.utils.Utils;
public class RunningAppsActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
......@@ -54,7 +58,8 @@ public class RunningAppsActivity extends AppCompatActivity implements SearchView
private RunningAppsAdapter mAdapter;
private static PackageManager mPackageManager;
private ProgressBar mProgressBar;
private ProgressIndicator mProgressIndicator;
private static boolean enableKillForSystem = false;
static class ProcessItem {
int pid;
......@@ -92,19 +97,40 @@ public class RunningAppsActivity extends AppCompatActivity implements SearchView
actionBar.setCustomView(searchView, layoutParams);
}
mPackageManager = getPackageManager();
mProgressBar = findViewById(R.id.progress_horizontal);
mProgressIndicator = findViewById(R.id.progress_linear);
ListView mListView = findViewById(android.R.id.list);
mListView.setTextFilterEnabled(true);
mListView.setDividerHeight(0);
mListView.setEmptyView(findViewById(android.R.id.empty));
mAdapter = new RunningAppsAdapter(this);
mListView.setAdapter(mAdapter);
new ProcessRefreshingThread().start();
mConstraint = null;
enableKillForSystem = (boolean) AppPref.get(this, AppPref.PREF_ENABLE_KILL_FOR_SYSTEM, AppPref.TYPE_BOOLEAN);
refresh();
}
@SuppressLint("RestrictedApi")
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_running_apps_actions, menu);
if (menu instanceof MenuBuilder) {
((MenuBuilder) menu).setOptionalIconsVisible(true);
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) finish();
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
case R.id.action_toggle_kill:
enableKillForSystem = !enableKillForSystem;
AppPref.getInstance(this).setPref(AppPref.PREF_ENABLE_KILL_FOR_SYSTEM, enableKillForSystem);
refresh();
return true;
}
return super.onOptionsItemSelected(item);
}
......@@ -162,6 +188,7 @@ public class RunningAppsActivity extends AppCompatActivity implements SearchView
private List<ProcessItem> mDefaultList;
private List<ProcessItem> mAdapterList;
private RunningAppsActivity mActivity;
private boolean isAdbMode = false;
private int mColorTransparent;
private int mColorSemiTransparent;
......@@ -179,6 +206,7 @@ public class RunningAppsActivity extends AppCompatActivity implements SearchView
void setDefaultList(List<ProcessItem> list) {
mDefaultList = list;
mAdapterList = list;
isAdbMode = AppPref.isAdbEnabled();
if(RunningAppsActivity.mConstraint != null
&& !RunningAppsActivity.mConstraint.equals("")) {
getFilter().filter(RunningAppsActivity.mConstraint);
......@@ -261,40 +289,51 @@ public class RunningAppsActivity extends AppCompatActivity implements SearchView
// Buttons
if (applicationInfo != null) {
holder.forceStopBtn.setVisibility(View.VISIBLE);
holder.forceStopBtn.setOnClickListener(v -> {
holder.forceStopBtn.setOnClickListener(v -> new Thread(() -> {
if (Runner.run(mActivity, String.format("am force-stop %s", applicationInfo.packageName)).isSuccessful()) {
mActivity.refresh();
mActivity.runOnUiThread(() -> mActivity.refresh());
} else {
Toast.makeText(mActivity, String.format(mActivity.getString(R.string.failed_to_stop), processName), Toast.LENGTH_LONG).show();
mActivity.runOnUiThread(() -> Toast.makeText(mActivity, String.format(mActivity.getString(R.string.failed_to_stop), processName), Toast.LENGTH_LONG).show());
}
});
int mode = AppOpsManager.MODE_DEFAULT;
try {
mode = new AppOpsService(mActivity).checkOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, applicationInfo.uid, applicationInfo.packageName);
} catch (Exception ignore) {}
if (mode != AppOpsManager.MODE_IGNORED) {
holder.disableBackgroundRunBtn.setVisibility(View.VISIBLE);
holder.disableBackgroundRunBtn.setOnClickListener(v -> {
try {
new AppOpsService(mActivity).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, applicationInfo.uid, applicationInfo.packageName, AppOpsManager.MODE_IGNORED);
StorageManager.getInstance(mActivity, applicationInfo.packageName).setAppOp(String.valueOf(AppOpsManager.OP_RUN_IN_BACKGROUND), AppOpsManager.MODE_IGNORED);
mActivity.refresh();
} catch (Exception e) {
Toast.makeText(mActivity, mActivity.getString(R.string.failed_to_disable_op), Toast.LENGTH_LONG).show();
}
}).start());
new Thread(() -> {
String mode = AppOpsManager.modeToName(AppOpsManager.MODE_DEFAULT);
try {
mode = new AppOpsService(mActivity).checkOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, applicationInfo.uid, applicationInfo.packageName);
} catch (Exception ignore) {}
String finalMode = mode;
mActivity.runOnUiThread(() -> {
if (!finalMode.equals(AppOpsManager.modeToName(AppOpsManager.MODE_IGNORED))) {
holder.disableBackgroundRunBtn.setVisibility(View.VISIBLE);
holder.disableBackgroundRunBtn.setOnClickListener(v -> new Thread(() -> {
try {
new AppOpsService(mActivity).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND,
applicationInfo.uid, applicationInfo.packageName, AppOpsManager.MODE_IGNORED);
try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(mActivity, applicationInfo.packageName)) {
cb.setAppOp(String.valueOf(AppOpsManager.OP_RUN_IN_BACKGROUND), AppOpsManager.MODE_IGNORED);
}
mActivity.runOnUiThread(() -> mActivity.refresh());
} catch (Exception e) {
mActivity.runOnUiThread(() -> Toast.makeText(mActivity, mActivity.getString(R.string.failed_to_disable_op), Toast.LENGTH_LONG).show());
}
}).start());
} else holder.disableBackgroundRunBtn.setVisibility(View.GONE);
});
} else holder.disableBackgroundRunBtn.setVisibility(View.GONE);
}).start();
} else {
holder.forceStopBtn.setVisibility(View.GONE);
holder.disableBackgroundRunBtn.setVisibility(View.GONE);
}
holder.killBtn.setOnClickListener(v -> {
if (Runner.run(mActivity, String.format(Locale.ROOT, "kill -9 %d", processItem.pid)).isSuccessful()) {
mActivity.refresh();
} else {
Toast.makeText(mActivity, String.format(mActivity.getString(R.string.failed_to_stop), processName), Toast.LENGTH_LONG).show();
}
});
if ((processItem.pid >= 10000 || enableKillForSystem) && !isAdbMode) {
holder.killBtn.setVisibility(View.VISIBLE);
holder.killBtn.setOnClickListener(v -> new Thread(() -> {
if (Runner.run(mActivity, String.format(Locale.ROOT, "kill -9 %d", processItem.pid)).isSuccessful()) {
mActivity.runOnUiThread(() -> mActivity.refresh());
} else {
mActivity.runOnUiThread(() -> Toast.makeText(mActivity, String.format(mActivity.getString(R.string.failed_to_stop), processName), Toast.LENGTH_LONG).show());
}
}).start());
} else holder.killBtn.setVisibility(View.GONE);
convertView.setBackgroundColor(position % 2 == 0 ? mColorSemiTransparent : mColorTransparent);
return convertView;
}
......@@ -409,7 +448,7 @@ public class RunningAppsActivity extends AppCompatActivity implements SearchView
List<ProcessItem> processItemList = new ArrayList<>(processList.values());
runOnUiThread(() -> {
mAdapter.setDefaultList(processItemList);
mProgressBar.setVisibility(View.GONE);
mProgressIndicator.hide();
});
}
}
......
......@@ -21,6 +21,7 @@ public class SettingsActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
setSupportActionBar(findViewById(R.id.toolbar));
findViewById(R.id.progress_linear).setVisibility(View.GONE);
appPref = AppPref.getInstance(this);
final SwitchMaterial rootSwitcher = findViewById(R.id.root_toggle_btn);
......
......@@ -16,11 +16,11 @@ import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.progressindicator.ProgressIndicator;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
......@@ -65,7 +65,7 @@ public class SharedPrefsActivity extends AppCompatActivity implements
private String mSharedPrefFile;
private File mTempSharedPrefFile;
private SharedPrefsListingAdapter mAdapter;
private ProgressBar mProgressBar;
private ProgressIndicator mProgressIndicator;
private HashMap<String, Object> mSharedPrefMap;
private static String mConstraint;
......@@ -107,8 +107,8 @@ public class SharedPrefsActivity extends AppCompatActivity implements
layoutParams.gravity = Gravity.END;
actionBar.setCustomView(searchView, layoutParams);
}
mProgressBar = findViewById(R.id.progress_horizontal);
mProgressBar.setVisibility(View.VISIBLE);
mProgressIndicator = findViewById(R.id.progress_linear);
mProgressIndicator.show();
ListView listView = findViewById(android.R.id.list);
listView.setTextFilterEnabled(true);
listView.setDividerHeight(0);
......@@ -289,7 +289,7 @@ public class SharedPrefsActivity extends AppCompatActivity implements
mSharedPrefMap = readSharedPref(mTempSharedPrefFile);
runOnUiThread(() -> {
mAdapter.setDefaultList(mSharedPrefMap);
mProgressBar.setVisibility(View.GONE);
mProgressIndicator.hide();
});
}
}
......
package io.github.muntashirakon.AppManager.adb;
import android.content.Context;
import android.util.Base64;
import com.tananaev.adblib.AdbBase64;
import com.tananaev.adblib.AdbConnection; <