Skip to content

Commit

Permalink
Show storage information, delete cache/data
Browse files Browse the repository at this point in the history
  • Loading branch information
MuntashirAkon committed Jun 16, 2020
1 parent 863005c commit 335c752
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 246 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package io.github.muntashirakon.AppManager.activities;

import android.annotation.SuppressLint;
import android.app.usage.StorageStats;
import android.app.usage.StorageStatsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageStatsObserver;
Expand All @@ -13,6 +16,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.Process;
import android.provider.Settings;
import android.text.format.Formatter;
import android.view.Menu;
Expand All @@ -32,6 +36,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -103,7 +108,7 @@ protected void onCreate(Bundle savedInstanceState) {
mHorizontalLayout = findViewById(R.id.horizontal_layout);
mTagCloud = findViewById(R.id.tag_cloud);
mAccentColor = Utils.getThemeColor(this, android.R.attr.colorAccent);
getPackageInfoOrFinish(mPackageName);
getPackageInfoOrFinish();
}

@Override
Expand All @@ -114,7 +119,7 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
return true;
case R.id.action_refresh_detail:
Toast.makeText(this, getString(R.string.refresh), Toast.LENGTH_SHORT).show();
getPackageInfoOrFinish(mPackageName);
getPackageInfoOrFinish();
return true;
case R.id.action_share_apk:
try {
Expand Down Expand Up @@ -177,14 +182,14 @@ public boolean onCreateOptionsMenu(Menu menu) {

@Override
public void onRefresh() {
getPackageInfoOrFinish(mPackageName);
getPackageInfoOrFinish();
mSwipeRefresh.setRefreshing(false);
}

@Override
protected void onResume() {
super.onResume();
getPackageInfoOrFinish(mPackageName);
getPackageInfoOrFinish();
}

/**
Expand Down Expand Up @@ -261,7 +266,7 @@ private void setHorizontalView() {
addToHorizontalLayout(R.string.disable, R.drawable.ic_block_black_24dp).setOnClickListener(v -> {
if (Shell.SU.run(String.format("pm disable %s", mPackageName)).isSuccessful()) {
// Refresh
getPackageInfoOrFinish(mPackageName);
getPackageInfoOrFinish();
} else {
Toast.makeText(mActivity, String.format(getString(R.string.failed_to_disable), mPackageLabel), Toast.LENGTH_LONG).show();
}
Expand All @@ -271,7 +276,7 @@ private void setHorizontalView() {
addToHorizontalLayout(R.string.enable, R.drawable.ic_baseline_get_app_24).setOnClickListener(v -> {
if (Shell.SU.run(String.format("pm enable %s", mPackageName)).isSuccessful()) {
// Refresh
getPackageInfoOrFinish(mPackageName);
getPackageInfoOrFinish();
} else {
Toast.makeText(mActivity, String.format(getString(R.string.failed_to_enable), mPackageLabel), Toast.LENGTH_LONG).show();
}
Expand All @@ -283,7 +288,7 @@ private void setHorizontalView() {
if (Shell.SH.run(String.format("am force-stop %s", mPackageName)).isSuccessful()
|| Shell.SU.run(String.format("am force-stop %s", mPackageName)).isSuccessful()) {
// Refresh
getPackageInfoOrFinish(mPackageName);
getPackageInfoOrFinish();
} else {
Toast.makeText(mActivity, String.format(getString(R.string.failed_to_stop), mPackageLabel), Toast.LENGTH_LONG).show();
}
Expand Down Expand Up @@ -467,11 +472,13 @@ private void setVerticalView() {
// Netstat
mList.addItemWithTitle(getString(R.string.netstats_msg), true);
mList.item_title.setTextColor(mAccentColor);

Tuple<String, String> uidNetStats = getNetStats(mApplicationInfo.uid);
mList.addItemWithTitleSubtitle(getString(R.string.netstats_transmitted), uidNetStats.getFirst(), ListItemCreator.SELECTABLE);
mList.addItemWithTitleSubtitle(getString(R.string.netstats_received), uidNetStats.getSecond(), ListItemCreator.SELECTABLE);
mList.addDivider();

// Storage and Cache
getPackageSizeInfo();
}

private List<String> getSharedPrefs(@NonNull String sourceDir) {
Expand Down Expand Up @@ -523,74 +530,118 @@ private View addToHorizontalLayout(@StringRes int stringResId, @DrawableRes int
private void getPackageSizeInfo() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
try {
@SuppressWarnings("JavaReflectionMemberAccess")
Method getPackageSizeInfo = PackageManager.class.getMethod(
Method getPackageSizeInfo = mPackageManager.getClass().getMethod(
"getPackageSizeInfo", String.class, IPackageStatsObserver.class);

getPackageSizeInfo.invoke(mPackageManager, mPackageName, new IPackageStatsObserver.Stub() {
@Override
public void onGetStatsCompleted(final PackageStats pStats, boolean succeeded) {
mActivity.runOnUiThread(() -> {
mPackageStats = pStats;
onPackageStatsLoaded();
setStorageInfo(mPackageStats.codeSize
+ mPackageStats.externalCodeSize, mPackageStats.dataSize
+ mPackageStats.externalDataSize, mPackageStats.cacheSize
+ mPackageStats.externalCacheSize, mPackageStats.externalObbSize,
mPackageStats.externalMediaSize);
});
}
});
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} else {
if (!Utils.checkUsageStatsPermission(this)) {
new AlertDialog.Builder(this, R.style.CustomDialog)
.setTitle(R.string.grant_usage_access)
.setMessage(R.string.grant_usage_acess_message)
.setPositiveButton(R.string.go, (dialog, which) -> startActivityForResult(new Intent(
Settings.ACTION_USAGE_ACCESS_SETTINGS), 0))
.setNegativeButton(getString(android.R.string.cancel), null)
.setCancelable(false)
.show();
return;
}
try {
StorageStatsManager storageStatsManager = (StorageStatsManager) getSystemService(Context.STORAGE_STATS_SERVICE);
StorageStats storageStats = storageStatsManager.queryStatsForPackage(mApplicationInfo.storageUuid, mPackageName, Process.myUserHandle());
// TODO: List obb and media size
long cacheSize = storageStats.getCacheBytes();
setStorageInfo(storageStats.getAppBytes(), storageStats.getDataBytes() - cacheSize, cacheSize, 0, 0);
} catch (IOException | PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}

private void onPackageStatsLoaded() {
if (mPackageStats == null)
return;

TextView sizeCodeView = findViewById(R.id.size_code);
sizeCodeView.setText(getReadableSize(mPackageStats.codeSize));

TextView sizeCacheView = findViewById(R.id.size_cache);
sizeCacheView.setText(getReadableSize(mPackageStats.cacheSize));

TextView sizeDataView = findViewById(R.id.size_data);
sizeDataView.setText(getReadableSize(mPackageStats.dataSize));

TextView sizeExtCodeView = findViewById(R.id.size_ext_code);
sizeExtCodeView.setText(getReadableSize(mPackageStats.externalCodeSize));

TextView sizeExtCacheView = findViewById(R.id.size_ext_cache);
sizeExtCacheView.setText(getReadableSize(mPackageStats.externalCacheSize));

TextView sizeExtDataView = findViewById(R.id.size_ext_data);
sizeExtDataView.setText(getReadableSize(mPackageStats.externalDataSize));

TextView sizeObb = findViewById(R.id.size_ext_obb);
sizeObb.setText(getReadableSize(mPackageStats.externalObbSize));

TextView sizeMedia = findViewById(R.id.size_ext_media);
sizeMedia.setText(getReadableSize(mPackageStats.externalMediaSize));
private void setStorageInfo(long codeSize, long dataSize, long cacheSize, long obbSize, long mediaSize) {
mList.addItemWithTitle(getString(R.string.storage_and_cache), true);
mList.item_title.setTextColor(mAccentColor);
// Code size
mList.addItemWithTitleSubtitle(getString(R.string.app_size), getReadableSize(codeSize),
ListItemCreator.SELECTABLE);
// Data size
mList.addItemWithTitleSubtitle(getString(R.string.data_size), getReadableSize(dataSize),
ListItemCreator.SELECTABLE);
mList.setOpen(v -> {
// Clear data
if(Shell.SU.run(String.format("pm clear %s", mPackageName)).isSuccessful()) {
getPackageInfoOrFinish();
}
});
mList.item_open.setImageDrawable(getDrawable(R.drawable.ic_delete_black_24dp));
// Cache size
mList.addItemWithTitleSubtitle(getString(R.string.cache_size), getReadableSize(cacheSize),
ListItemCreator.SELECTABLE);
mList.setOpen(v -> {
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) {
if (!mApplicationInfo.dataDir.equals(mApplicationInfo.deviceProtectedDataDir)) {
command.append(String.format(" %s/cache %s/code_cache",
mApplicationInfo.deviceProtectedDataDir, mApplicationInfo.deviceProtectedDataDir));
}
}
File[] cacheDirs = getExternalCacheDirs();
for(File cacheDir: cacheDirs) {
String extCache = cacheDir.getAbsolutePath().replace(getPackageName(), mPackageName);
command.append(" ").append(extCache);
}
if (Shell.SU.run(command.toString()).isSuccessful()) {
getPackageInfoOrFinish();
}
});
mList.item_open.setImageDrawable(getDrawable(R.drawable.ic_delete_black_24dp));
// OBB size
if (obbSize != 0)
mList.addItemWithTitleSubtitle(getString(R.string.obb_size), getReadableSize(obbSize),
ListItemCreator.SELECTABLE);
// Media size
if (mediaSize != 0)
mList.addItemWithTitleSubtitle(getString(R.string.media_size), getReadableSize(mediaSize),
ListItemCreator.SELECTABLE);
mList.addItemWithTitleSubtitle(getString(R.string.total_size), getReadableSize(codeSize
+ dataSize + cacheSize + obbSize + mediaSize), ListItemCreator.SELECTABLE);
mList.addDivider();
}

/**
* Get package info.
* @param packageName Package name (e.g. com.android.wallpaper)
*/
@SuppressLint("PackageManagerGetSignatures")
private void getPackageInfoOrFinish(String packageName) {
private void getPackageInfoOrFinish() {
try {
final int signingCertFlag;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
signingCertFlag = PackageManager.GET_SIGNING_CERTIFICATES;
} else {
signingCertFlag = PackageManager.GET_SIGNATURES;
}
mPackageInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS
mPackageInfo = mPackageManager.getPackageInfo(mPackageName, PackageManager.GET_PERMISSIONS
| PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS
| PackageManager.GET_SERVICES | PackageManager.GET_URI_PERMISSION_PATTERNS
| signingCertFlag | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_SHARED_LIBRARY_FILES);

if (mPackageInfo == null) {
Toast.makeText(this, mPackageName + ": " + getString(R.string.app_not_installed), Toast.LENGTH_LONG).show();
Toast.makeText(this, this.mPackageName + ": " + getString(R.string.app_not_installed), Toast.LENGTH_LONG).show();
finish();
return;
}
Expand All @@ -604,8 +655,6 @@ private void getPackageInfoOrFinish(String packageName) {
setHeaderView();
setHorizontalView();
setVerticalView();
// Load package size info
getPackageSizeInfo();
} catch (PackageManager.NameNotFoundException e) {
finish();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package io.github.muntashirakon.AppManager.activities;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Intent;
Expand Down Expand Up @@ -41,6 +39,7 @@
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.utils.Utils;

public class AppUsageActivity extends AppCompatActivity {
private static final String SYS_USAGE_STATS_SERVICE = "usagestats";
Expand Down Expand Up @@ -110,7 +109,7 @@ public void onNothingSelected(AdapterView<?> parent) {}
protected void onStart() {
super.onStart();
// Check permission
if (!checkUsageStatsPermission()) promptForUsageStatsPermission();
if (!Utils.checkUsageStatsPermission(this)) promptForUsageStatsPermission();
else getAppUsage();
}

Expand All @@ -126,7 +125,7 @@ private void getAppUsage() {
Calendar cal = Calendar.getInstance();
switch (current_interval) {
case USAGE_DAILY:
cal.add(Calendar.MINUTE, -1);
cal.add(Calendar.HOUR_OF_DAY, -cal.get(Calendar.HOUR_OF_DAY));
break;
case USAGE_WEEKLY:
cal.add(Calendar.DAY_OF_YEAR, -7);
Expand Down Expand Up @@ -179,26 +178,6 @@ private void promptForUsageStatsPermission() {
.show();
}

private boolean checkUsageStatsPermission() {
AppOpsManager appOpsManager = (AppOpsManager) getSystemService(APP_OPS_SERVICE);
assert appOpsManager != null;
final int mode;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
mode = appOpsManager.unsafeCheckOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
} else {
//noinspection deprecation
mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
}
if (mode == AppOpsManager.MODE_DEFAULT
&& android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
return checkCallingOrSelfPermission(Manifest.permission.PACKAGE_USAGE_STATS)
== PackageManager.PERMISSION_GRANTED;
}
return mode == AppOpsManager.MODE_ALLOWED;
}

private void setUsageSummary() {
TextView timeUsed = findViewById(R.id.time_used);
TextView timeRange = findViewById(R.id.time_range);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package io.github.muntashirakon.AppManager.utils;

import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
Expand Down Expand Up @@ -44,6 +47,26 @@
import androidx.annotation.NonNull;

public class Utils {
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public static boolean checkUsageStatsPermission(@NonNull Context context) {
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
assert appOpsManager != null;
final int mode;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
mode = appOpsManager.unsafeCheckOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), context.getPackageName());
} else {
//noinspection deprecation
mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), context.getPackageName());
}
if (mode == AppOpsManager.MODE_DEFAULT
&& android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
return context.checkCallingOrSelfPermission(Manifest.permission.PACKAGE_USAGE_STATS)
== PackageManager.PERMISSION_GRANTED;
}
return mode == AppOpsManager.MODE_ALLOWED;
}

public static int getArrayLengthSafely(Object[] array) {
return array == null ? 0 : array.length;
Expand Down
6 changes: 1 addition & 5 deletions app/src/main/res/layout/activity_app_info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,7 @@
android:id="@+id/details_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

</LinearLayout>

<include layout="@layout/app_info_size" />
android:orientation="vertical" />

</LinearLayout>
</ScrollView>
Expand Down
Loading

0 comments on commit 335c752

Please sign in to comment.