Skip to content
This repository has been archived by the owner on May 20, 2019. It is now read-only.

Development #59

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions CacheCleaner/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@ import org.ajoberstar.grgit.Grgit
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
// classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'org.ajoberstar:gradle-git:1.4.2'
}
}
apply plugin: 'com.android.application'

repositories {
mavenCentral()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}

ext {
Expand All @@ -22,22 +31,22 @@ ext {
}

android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
compileSdkVersion 27
buildToolsVersion '27.0.3'

defaultConfig {
applicationId "com.frozendevs.cache.cleaner"
minSdkVersion 9
targetSdkVersion 23
minSdkVersion 15
targetSdkVersion 27
versionCode = gitVersionCode
versionName = gitVersionName

vectorDrawables.useSupportLibrary = true
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

buildTypes {
Expand All @@ -57,10 +66,10 @@ android {
}

dependencies {
compile('com.android.support:support-v4:23.4.0')
compile('com.android.support:appcompat-v7:23.4.0@aar')
compile('com.android.support:recyclerview-v7:23.4.0@aar')
compile('com.android.support:support-vector-drawable:23.4.0@aar')
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:support-vector-drawable:27.1.1'
}

if (project.hasProperty("CacheCleaner.signing") &&
Expand Down
5 changes: 5 additions & 0 deletions CacheCleaner/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.frozendevs.cache.cleaner"
android:installLocation="internalOnly">

Expand All @@ -8,6 +9,10 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />

<supports-screens
android:anyDensity="true"
android:largeScreens="true"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,56 @@
package com.frozendevs.cache.cleaner.activity;

import android.app.AppOpsManager;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.frozendevs.cache.cleaner.R;

public class CleanerActivity extends AppCompatActivity {
import java.util.List;

public class CleanerActivity extends AppCompatActivity {
public final static int USAGE_ACCESS_SETTINGS = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.cleaner_activity);
}


public static boolean checkUsageStatsEnabled(Context context) {
// Usage Stats is theoretically available on API v19+, but official/reliable support starts with API v21.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return false;
}

final AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);

if (appOpsManager == null) {
return false;
}

final int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), context.getPackageName());
if (mode != AppOpsManager.MODE_ALLOWED) {
return false;
}

// Verify that access is possible. Some devices "lie" and return MODE_ALLOWED even when it's not.
final long now = System.currentTimeMillis();
final UsageStatsManager mUsageStatsManager;
List<UsageStats> stats = null;

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
if (mUsageStatsManager != null) {
stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, now - 1000 * 10, now);
}
}

return (stats != null && !stats.isEmpty());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.frozendevs.cache.cleaner.fragment;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
Expand All @@ -15,6 +17,7 @@
import android.os.IBinder;
import android.os.StatFs;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
Expand All @@ -34,6 +37,7 @@
import android.widget.Toast;

import com.frozendevs.cache.cleaner.R;
import com.frozendevs.cache.cleaner.activity.CleanerActivity;
import com.frozendevs.cache.cleaner.activity.SettingsActivity;
import com.frozendevs.cache.cleaner.model.AppsListItem;
import com.frozendevs.cache.cleaner.model.CleanerService;
Expand All @@ -43,6 +47,8 @@

import java.util.List;

import static com.frozendevs.cache.cleaner.activity.CleanerActivity.USAGE_ACCESS_SETTINGS;

public class CleanerFragment extends Fragment implements CleanerService.OnActionListener {

private static final int REQUEST_STORAGE = 0;
Expand Down Expand Up @@ -96,10 +102,10 @@ public void onServiceDisconnected(ComponentName name) {
}
};


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setHasOptionsMenu(true);
setRetainInstance(true);

Expand All @@ -123,6 +129,59 @@ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
}
});

startService();
}


void startService() {

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

boolean usageStats = CleanerActivity.checkUsageStatsEnabled(getActivity());

if (usageStats) {

startCleanerService();

} else {

showDialog(getActivity(), "Usage Access Settings", "You need to allow Usage Access Settings to access cache of all app.");
}
} else {
startCleanerService();
}
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void showDialog(Activity activity, String title, CharSequence message) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);

if (title != null) builder.setTitle(title);

builder.setMessage(message);
builder.setPositiveButton("Allow", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialogInterface, int i) {

Intent usageIntent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivityForResult(usageIntent, USAGE_ACCESS_SETTINGS);
}
});
builder.setCancelable(false);
builder.show();
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == USAGE_ACCESS_SETTINGS)
startService();

}

private void startCleanerService() {
getActivity().getApplication().bindService(new Intent(getActivity(), CleanerService.class),
mServiceConnection, Context.BIND_AUTO_CREATE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import android.Manifest;
import android.app.Service;
import android.app.usage.StorageStats;
import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
Expand All @@ -17,6 +19,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.StatFs;
import android.os.storage.StorageManager;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.widget.Toast;
Expand All @@ -30,6 +33,8 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;

import static android.content.pm.PackageManager.GET_META_DATA;

public class CleanerService extends Service {

public static final String ACTION_CLEAN_AND_EXIT = "com.frozendevs.cache.cleaner.CLEAN_AND_EXIT";
Expand Down Expand Up @@ -83,36 +88,69 @@ protected List<AppsListItem> doInBackground(Void... params) {

publishProgress(0, packages.size());

final CountDownLatch countDownLatch = new CountDownLatch(packages.size());

final List<AppsListItem> apps = new ArrayList<>();

try {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

final StorageStatsManager storageStatsManager = (StorageStatsManager) getSystemService(Context.STORAGE_STATS_SERVICE);

final StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);

for (ApplicationInfo pkg : packages) {
mGetPackageSizeInfoMethod.invoke(getPackageManager(), pkg.packageName,
new IPackageStatsObserver.Stub() {

@Override
public void onGetStatsCompleted(PackageStats pStats,
boolean succeeded)
throws RemoteException {
synchronized (apps) {
publishProgress(++mAppCount, packages.size());
try {

mCacheSize += addPackage(apps, pStats, succeeded);
}
ApplicationInfo info = getPackageManager().getApplicationInfo(pkg.packageName, GET_META_DATA);
StorageStats storageStats = storageStatsManager.queryStatsForUid(info.storageUuid, info.uid);

publishProgress(++mAppCount, packages.size());
long cacheSize = storageStats.getCacheBytes();
mCacheSize += cacheSize;

try {
PackageManager packageManager = getPackageManager();

apps.add(new AppsListItem(pkg.packageName,
packageManager.getApplicationLabel(info).toString(),
packageManager.getApplicationIcon(pkg.packageName),
cacheSize));
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}

synchronized (countDownLatch) {
countDownLatch.countDown();
} catch (Exception ignored) {
}
}
} else {
final CountDownLatch countDownLatch = new CountDownLatch(packages.size());
try {
for (ApplicationInfo pkg : packages) {
mGetPackageSizeInfoMethod.invoke(getPackageManager(), pkg.packageName,
new IPackageStatsObserver.Stub() {

@Override
public void onGetStatsCompleted(PackageStats pStats,
boolean succeeded)
throws RemoteException {
synchronized (apps) {
publishProgress(++mAppCount, packages.size());

mCacheSize += addPackage(apps, pStats, succeeded);
}

synchronized (countDownLatch) {
countDownLatch.countDown();
}
}
}
}
);
}
);
}

countDownLatch.await();
} catch (InvocationTargetException | InterruptedException | IllegalAccessException e) {
e.printStackTrace();
countDownLatch.await();
} catch (InvocationTargetException | InterruptedException | IllegalAccessException e) {
e.printStackTrace();
}
}

return new ArrayList<>(apps);
Expand Down Expand Up @@ -339,8 +377,7 @@ public void onCleanStarted(Context context) {
public void onCleanCompleted(Context context, boolean succeeded) {
if (succeeded) {
Log.d(TAG, "Cache cleaned");
}
else {
} else {
Log.e(TAG, "Could not clean the cache");
}

Expand Down
9 changes: 9 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
repositories {
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
}