├── .editorconfig
├── .gitignore
├── .gitlab-ci.yml
├── .travis.yml
├── CacheCleaner
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── aidl
│ └── android
│ │ └── content
│ │ └── pm
│ │ ├── IPackageDataObserver.aidl
│ │ ├── IPackageStatsObserver.aidl
│ │ └── PackageStats.aidl
│ ├── assets
│ └── html
│ │ └── licenses.html
│ ├── java
│ └── com
│ │ ├── android
│ │ └── settings
│ │ │ └── applications
│ │ │ └── LinearColorBar.java
│ │ └── frozendevs
│ │ └── cache
│ │ └── cleaner
│ │ ├── activity
│ │ ├── CleanerActivity.java
│ │ └── SettingsActivity.java
│ │ ├── fragment
│ │ └── CleanerFragment.java
│ │ ├── model
│ │ ├── AppsListItem.java
│ │ ├── BroadcastReceiver.java
│ │ ├── CleanerService.java
│ │ └── adapter
│ │ │ └── AppsListAdapter.java
│ │ └── widget
│ │ ├── DividerDecoration.java
│ │ └── RecyclerView.java
│ └── res
│ ├── drawable-hdpi
│ ├── ic_launcher_cache_cleaner.png
│ ├── ic_menu_delete.png
│ ├── ic_menu_refresh.png
│ └── ic_menu_search.png
│ ├── drawable-mdpi
│ ├── ic_launcher_cache_cleaner.png
│ ├── ic_menu_delete.png
│ ├── ic_menu_refresh.png
│ └── ic_menu_search.png
│ ├── drawable-xhdpi
│ ├── ic_launcher_cache_cleaner.png
│ ├── ic_menu_delete.png
│ ├── ic_menu_refresh.png
│ └── ic_menu_search.png
│ ├── drawable-xxhdpi
│ ├── ic_launcher_cache_cleaner.png
│ ├── ic_menu_delete.png
│ ├── ic_menu_refresh.png
│ └── ic_menu_search.png
│ ├── drawable-xxxhdpi
│ ├── ic_launcher_cache_cleaner.png
│ ├── ic_menu_delete.png
│ ├── ic_menu_refresh.png
│ └── ic_menu_search.png
│ ├── drawable
│ └── dotted_line.xml
│ ├── layout
│ ├── apps_list_header.xml
│ ├── cleaner_activity.xml
│ ├── cleaner_fragment.xml
│ ├── dotted_line.xml
│ └── list_item.xml
│ ├── menu
│ └── main_menu.xml
│ ├── values-es
│ └── strings.xml
│ ├── values-fr
│ └── strings.xml
│ ├── values-hu
│ └── strings.xml
│ ├── values-ja
│ └── strings.xml
│ ├── values-pt
│ └── strings.xml
│ ├── values-sk
│ └── strings.xml
│ ├── values-sr
│ └── strings.xml
│ ├── values-sw600dp
│ └── dimens.xml
│ ├── values-sw720dp-land
│ └── dimens.xml
│ ├── values-sw720dp
│ └── dimens.xml
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── urls.xml
│ └── xml
│ ├── settings.xml
│ └── settings_about.xml
├── LICENSE
├── README.md
├── build.gradle
└── settings.gradle
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Copying and distribution of this file, with or without modification,
2 | # are permitted in any medium without royalty provided this notice is
3 | # preserved. This file is offered as-is, without any warranty.
4 |
5 | # EditorConfig
6 | # http://EditorConfig.org
7 |
8 | # top-most EditorConfig file
9 | root = true
10 |
11 | [*]
12 | end_of_line = lf
13 | insert_final_newline = true
14 | charset = utf-8
15 |
16 | [*.java,*.xml]
17 | indent_style = space
18 | indent_size = 4
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # IntelliJ
2 | build/
3 | .idea/
4 | *.iml
5 | *.properties
6 |
7 | # Gradle
8 | .gradle/
9 | gradle*
10 |
11 | # Temp
12 | *~
13 | \#*
14 | .\#*
15 | *.autosave
16 |
17 | # Windows
18 | Thumbs.db
19 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | stages:
2 | - build
3 |
4 | build:
5 | stage: build
6 | script:
7 | - gradle build
8 | artifacts:
9 | paths:
10 | - CacheCleaner/build/outputs/
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk7
3 | sudo: false
4 |
5 | before_script:
6 | - wget https://services.gradle.org/distributions/gradle-2.12-bin.zip
7 | - unzip gradle-2.12-bin.zip
8 | - export GRADLE_HOME=$PWD/gradle-2.12
9 | - export PATH=$GRADLE_HOME/bin:$PATH
10 |
11 | android:
12 | components:
13 | - tools
14 | - platform-tools
15 | - build-tools-23.0.3
16 | - android-23
17 | - extra-android-m2repository
18 |
19 | script: gradle build
20 |
--------------------------------------------------------------------------------
/CacheCleaner/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/CacheCleaner/build.gradle:
--------------------------------------------------------------------------------
1 | import org.ajoberstar.grgit.Grgit
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.1.2'
9 | classpath 'org.ajoberstar:gradle-git:1.4.2'
10 | }
11 | }
12 | apply plugin: 'com.android.application'
13 |
14 | repositories {
15 | mavenCentral()
16 | }
17 |
18 | ext {
19 | git = Grgit.open()
20 | gitVersionCode = git.tag.list().size() + 1
21 | gitVersionName = "${git.describe()}"
22 | }
23 |
24 | android {
25 | compileSdkVersion 23
26 | buildToolsVersion "23.0.3"
27 |
28 | defaultConfig {
29 | applicationId "com.frozendevs.cache.cleaner"
30 | minSdkVersion 9
31 | targetSdkVersion 23
32 | versionCode = gitVersionCode
33 | versionName = gitVersionName
34 |
35 | vectorDrawables.useSupportLibrary = true
36 | }
37 |
38 | compileOptions {
39 | sourceCompatibility JavaVersion.VERSION_1_7
40 | targetCompatibility JavaVersion.VERSION_1_7
41 | }
42 |
43 | buildTypes {
44 | release {
45 | minifyEnabled true
46 | shrinkResources true
47 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
48 | }
49 | }
50 |
51 | lintOptions {
52 | ignore 'GoogleAppIndexingWarning', 'UnusedAttribute'
53 | textOutput 'stdout'
54 | textReport true
55 | warning 'MissingTranslation'
56 | }
57 | }
58 |
59 | dependencies {
60 | compile('com.android.support:support-v4:23.4.0')
61 | compile('com.android.support:appcompat-v7:23.4.0@aar')
62 | compile('com.android.support:recyclerview-v7:23.4.0@aar')
63 | compile('com.android.support:support-vector-drawable:23.4.0@aar')
64 | }
65 |
66 | if (project.hasProperty("CacheCleaner.signing") &&
67 | file(project.property("CacheCleaner.signing") + ".gradle").exists()) {
68 | apply from: project.property("CacheCleaner.signing") + ".gradle";
69 | }
70 |
--------------------------------------------------------------------------------
/CacheCleaner/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | -dontobfuscate
13 |
14 | # SearchView
15 | -keep class android.support.v7.widget.SearchView { *; }
16 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
18 |
19 |
26 |
27 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/aidl/android/content/pm/IPackageDataObserver.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | **
3 | ** Copyright 2007, The Android Open Source Project
4 | **
5 | ** Licensed under the Apache License, Version 2.0 (the "License");
6 | ** you may not use this file except in compliance with the License.
7 | ** You may obtain a copy of the License at
8 | **
9 | ** http://www.apache.org/licenses/LICENSE-2.0
10 | **
11 | ** Unless required by applicable law or agreed to in writing, software
12 | ** distributed under the License is distributed on an "AS IS" BASIS,
13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | ** See the License for the specific language governing permissions and
15 | ** limitations under the License.
16 | */
17 |
18 | package android.content.pm;
19 |
20 | /**
21 | * API for package data change related callbacks from the Package Manager.
22 | * Some usage scenarios include deletion of cache directory, generate
23 | * statistics related to code, data, cache usage(TODO)
24 | * {@hide}
25 | */
26 | oneway interface IPackageDataObserver {
27 | void onRemoveCompleted(in String packageName, boolean succeeded);
28 | }
29 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/aidl/android/content/pm/IPackageStatsObserver.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | **
3 | ** Copyright 2007, The Android Open Source Project
4 | **
5 | ** Licensed under the Apache License, Version 2.0 (the "License");
6 | ** you may not use this file except in compliance with the License.
7 | ** You may obtain a copy of the License at
8 | **
9 | ** http://www.apache.org/licenses/LICENSE-2.0
10 | **
11 | ** Unless required by applicable law or agreed to in writing, software
12 | ** distributed under the License is distributed on an "AS IS" BASIS,
13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | ** See the License for the specific language governing permissions and
15 | ** limitations under the License.
16 | */
17 |
18 | package android.content.pm;
19 |
20 | import android.content.pm.PackageStats;
21 | /**
22 | * API for package data change related callbacks from the Package Manager.
23 | * Some usage scenarios include deletion of cache directory, generate
24 | * statistics related to code, data, cache usage(TODO)
25 | * {@hide}
26 | */
27 | oneway interface IPackageStatsObserver {
28 |
29 | void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);
30 | }
31 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/aidl/android/content/pm/PackageStats.aidl:
--------------------------------------------------------------------------------
1 | /* //device/java/android/android/view/WindowManager.aidl
2 | **
3 | ** Copyright 2007, The Android Open Source Project
4 | **
5 | ** Licensed under the Apache License, Version 2.0 (the "License");
6 | ** you may not use this file except in compliance with the License.
7 | ** You may obtain a copy of the License at
8 | **
9 | ** http://www.apache.org/licenses/LICENSE-2.0
10 | **
11 | ** Unless required by applicable law or agreed to in writing, software
12 | ** distributed under the License is distributed on an "AS IS" BASIS,
13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | ** See the License for the specific language governing permissions and
15 | ** limitations under the License.
16 | */
17 |
18 | package android.content.pm;
19 |
20 | parcelable PackageStats;
21 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/assets/html/licenses.html:
--------------------------------------------------------------------------------
1 |
2 | Notices for libraries:
3 |
4 | - support-v4
5 | - appcompat-v7
6 | - recyclerview-v7
7 |
8 |
9 | Copyright (C) 2005-2013 The Android Open Source Project
10 |
11 | Licensed under the Apache License, Version 2.0 (the "License");
12 | you may not use this file except in compliance with the License.
13 | You may obtain a copy of the License at
14 |
15 | http://www.apache.org/licenses/LICENSE-2.0
16 |
17 | Unless required by applicable law or agreed to in writing, software
18 | distributed under the License is distributed on an "AS IS" BASIS,
19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | See the License for the specific language governing permissions and
21 | limitations under the License.
22 |
23 | Notices for files:
24 |
25 | - LinearColorBar.java
26 | - IPackageDataObserver.aidl
27 | - IPackageStatsObserver.aidl
28 | - PackageStats.aidl
29 |
30 |
31 | Copyright (C) 2007, The Android Open Source Project
32 |
33 | Licensed under the Apache License, Version 2.0 (the "License");
34 | you may not use this file except in compliance with the License.
35 | You may obtain a copy of the License at
36 |
37 | http://www.apache.org/licenses/LICENSE-2.0
38 |
39 | Unless required by applicable law or agreed to in writing, software
40 | distributed under the License is distributed on an "AS IS" BASIS,
41 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42 | See the License for the specific language governing permissions and
43 | limitations under the License.
44 |
45 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/android/settings/applications/LinearColorBar.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.android.settings.applications;
5 |
6 | import android.content.Context;
7 | import android.graphics.Canvas;
8 | import android.graphics.LinearGradient;
9 | import android.graphics.Paint;
10 | import android.graphics.Path;
11 | import android.graphics.Rect;
12 | import android.graphics.Shader;
13 | import android.util.AttributeSet;
14 | import android.util.DisplayMetrics;
15 | import android.view.MotionEvent;
16 | import android.widget.LinearLayout;
17 |
18 | public class LinearColorBar extends LinearLayout {
19 | static final int LEFT_COLOR = 0xff009688;
20 | static final int MIDDLE_COLOR = 0xff009688;
21 | static final int RIGHT_COLOR = 0xffced7db;
22 | static final int GRAY_COLOR = 0xff555555;
23 | static final int WHITE_COLOR = 0xffffffff;
24 |
25 | private float mRedRatio;
26 | private float mYellowRatio;
27 | private float mGreenRatio;
28 |
29 | private int mLeftColor = LEFT_COLOR;
30 | private int mMiddleColor = MIDDLE_COLOR;
31 | private int mRightColor = RIGHT_COLOR;
32 |
33 | private boolean mShowIndicator = true;
34 | private boolean mShowingGreen;
35 |
36 | private OnRegionTappedListener mOnRegionTappedListener;
37 | private int mColoredRegions = REGION_RED | REGION_YELLOW | REGION_GREEN;
38 |
39 | final Rect mRect = new Rect();
40 | final Paint mPaint = new Paint();
41 |
42 | int mLastInterestingLeft, mLastInterestingRight;
43 | int mLineWidth;
44 |
45 | int mLastLeftDiv, mLastRightDiv;
46 | int mLastRegion;
47 |
48 | final Path mColorPath = new Path();
49 | final Path mEdgePath = new Path();
50 | final Paint mColorGradientPaint = new Paint();
51 | final Paint mEdgeGradientPaint = new Paint();
52 |
53 | public static final int REGION_RED = 1<<0;
54 | public static final int REGION_YELLOW = 1<<1;
55 | public static final int REGION_GREEN = 1<<2;
56 | public static final int REGION_ALL = REGION_RED | REGION_YELLOW | REGION_GREEN;
57 |
58 | public interface OnRegionTappedListener {
59 | public void onRegionTapped(int region);
60 | }
61 |
62 | public LinearColorBar(Context context, AttributeSet attrs) {
63 | super(context, attrs);
64 | setWillNotDraw(false);
65 | mPaint.setStyle(Paint.Style.FILL);
66 | mColorGradientPaint.setStyle(Paint.Style.FILL);
67 | mColorGradientPaint.setAntiAlias(true);
68 | mEdgeGradientPaint.setStyle(Paint.Style.STROKE);
69 | mLineWidth = getResources().getDisplayMetrics().densityDpi >= DisplayMetrics.DENSITY_HIGH
70 | ? 2 : 1;
71 | mEdgeGradientPaint.setStrokeWidth(mLineWidth);
72 | mEdgeGradientPaint.setAntiAlias(true);
73 |
74 | }
75 |
76 | public void setOnRegionTappedListener(OnRegionTappedListener listener) {
77 | if (listener != mOnRegionTappedListener) {
78 | mOnRegionTappedListener = listener;
79 | setClickable(listener != null);
80 | }
81 | }
82 |
83 | public void setColoredRegions(int regions) {
84 | mColoredRegions = regions;
85 | invalidate();
86 | }
87 |
88 | public void setRatios(float red, float yellow, float green) {
89 | mRedRatio = red;
90 | mYellowRatio = yellow;
91 | mGreenRatio = green;
92 | invalidate();
93 | }
94 |
95 | public void setColors(int red, int yellow, int green) {
96 | mLeftColor = red;
97 | mMiddleColor = yellow;
98 | mRightColor = green;
99 | updateIndicator();
100 | invalidate();
101 | }
102 |
103 | public void setShowIndicator(boolean showIndicator) {
104 | mShowIndicator = showIndicator;
105 | updateIndicator();
106 | invalidate();
107 | }
108 |
109 | public void setShowingGreen(boolean showingGreen) {
110 | if (mShowingGreen != showingGreen) {
111 | mShowingGreen = showingGreen;
112 | updateIndicator();
113 | invalidate();
114 | }
115 | }
116 |
117 | private void updateIndicator() {
118 | int off = getPaddingTop() - getPaddingBottom();
119 | if (off < 0) off = 0;
120 | mRect.top = off;
121 | mRect.bottom = getHeight();
122 | if (!mShowIndicator) {
123 | return;
124 | }
125 | if (mShowingGreen) {
126 | mColorGradientPaint.setShader(new LinearGradient(
127 | 0, 0, 0, off-2, mRightColor &0xffffff, mRightColor, Shader.TileMode.CLAMP));
128 | } else {
129 | mColorGradientPaint.setShader(new LinearGradient(
130 | 0, 0, 0, off-2, mMiddleColor&0xffffff, mMiddleColor, Shader.TileMode.CLAMP));
131 | }
132 | mEdgeGradientPaint.setShader(new LinearGradient(
133 | 0, 0, 0, off/2, 0x00a0a0a0, 0xffa0a0a0, Shader.TileMode.CLAMP));
134 | }
135 |
136 | @Override
137 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
138 | super.onSizeChanged(w, h, oldw, oldh);
139 | updateIndicator();
140 | }
141 |
142 | @Override
143 | public boolean onTouchEvent(MotionEvent event) {
144 | if (mOnRegionTappedListener != null) {
145 | switch (event.getAction()) {
146 | case MotionEvent.ACTION_DOWN: {
147 | final int x = (int) event.getX();
148 | if (x < mLastLeftDiv) {
149 | mLastRegion = REGION_RED;
150 | } else if (x < mLastRightDiv) {
151 | mLastRegion = REGION_YELLOW;
152 | } else {
153 | mLastRegion = REGION_GREEN;
154 | }
155 | invalidate();
156 | } break;
157 | }
158 | }
159 | return super.onTouchEvent(event);
160 | }
161 |
162 | @Override
163 | protected void dispatchSetPressed(boolean pressed) {
164 | invalidate();
165 | }
166 |
167 | @Override
168 | public boolean performClick() {
169 | if (mOnRegionTappedListener != null && mLastRegion != 0) {
170 | mOnRegionTappedListener.onRegionTapped(mLastRegion);
171 | mLastRegion = 0;
172 | }
173 | return super.performClick();
174 | }
175 |
176 | private int pickColor(int color, int region) {
177 | if (isPressed() && (mLastRegion®ion) != 0) {
178 | return WHITE_COLOR;
179 | }
180 | if ((mColoredRegions®ion) == 0) {
181 | return GRAY_COLOR;
182 | }
183 | return color;
184 | }
185 |
186 | @Override
187 | protected void onDraw(Canvas canvas) {
188 | super.onDraw(canvas);
189 |
190 | int width = getWidth();
191 |
192 | int left = 0;
193 |
194 | int right = left + (int)(width*mRedRatio);
195 | int right2 = right + (int)(width*mYellowRatio);
196 | int right3 = right2 + (int)(width*mGreenRatio);
197 |
198 | int indicatorLeft, indicatorRight;
199 | if (mShowingGreen) {
200 | indicatorLeft = right2;
201 | indicatorRight = right3;
202 | } else {
203 | indicatorLeft = right;
204 | indicatorRight = right2;
205 | }
206 |
207 | if (mLastInterestingLeft != indicatorLeft || mLastInterestingRight != indicatorRight) {
208 | mColorPath.reset();
209 | mEdgePath.reset();
210 | if (mShowIndicator && indicatorLeft < indicatorRight) {
211 | final int midTopY = mRect.top;
212 | final int midBottomY = 0;
213 | final int xoff = 2;
214 | mColorPath.moveTo(indicatorLeft, mRect.top);
215 | mColorPath.cubicTo(indicatorLeft, midBottomY,
216 | -xoff, midTopY,
217 | -xoff, 0);
218 | mColorPath.lineTo(width+xoff-1, 0);
219 | mColorPath.cubicTo(width+xoff-1, midTopY,
220 | indicatorRight, midBottomY,
221 | indicatorRight, mRect.top);
222 | mColorPath.close();
223 | final float lineOffset = mLineWidth+.5f;
224 | mEdgePath.moveTo(-xoff+lineOffset, 0);
225 | mEdgePath.cubicTo(-xoff+lineOffset, midTopY,
226 | indicatorLeft+lineOffset, midBottomY,
227 | indicatorLeft+lineOffset, mRect.top);
228 | mEdgePath.moveTo(width+xoff-1-lineOffset, 0);
229 | mEdgePath.cubicTo(width+xoff-1-lineOffset, midTopY,
230 | indicatorRight-lineOffset, midBottomY,
231 | indicatorRight-lineOffset, mRect.top);
232 | }
233 | mLastInterestingLeft = indicatorLeft;
234 | mLastInterestingRight = indicatorRight;
235 | }
236 |
237 | if (!mEdgePath.isEmpty()) {
238 | canvas.drawPath(mEdgePath, mEdgeGradientPaint);
239 | canvas.drawPath(mColorPath, mColorGradientPaint);
240 | }
241 |
242 | if (left < right) {
243 | mRect.left = left;
244 | mRect.right = right;
245 | mPaint.setColor(pickColor(mLeftColor, REGION_RED));
246 | canvas.drawRect(mRect, mPaint);
247 | width -= (right-left);
248 | left = right;
249 | }
250 |
251 | mLastLeftDiv = right;
252 | mLastRightDiv = right2;
253 |
254 | right = right2;
255 |
256 | if (left < right) {
257 | mRect.left = left;
258 | mRect.right = right;
259 | mPaint.setColor(pickColor(mMiddleColor, REGION_YELLOW));
260 | canvas.drawRect(mRect, mPaint);
261 | width -= (right-left);
262 | left = right;
263 | }
264 |
265 |
266 | right = left + width;
267 | if (left < right) {
268 | mRect.left = left;
269 | mRect.right = right;
270 | mPaint.setColor(pickColor(mRightColor, REGION_GREEN));
271 | canvas.drawRect(mRect, mPaint);
272 | }
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/activity/CleanerActivity.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.activity;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 |
6 | import com.frozendevs.cache.cleaner.R;
7 |
8 | public class CleanerActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 |
14 | setContentView(R.layout.cleaner_activity);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/activity/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.activity;
2 |
3 | import android.content.res.Configuration;
4 | import android.os.Bundle;
5 | import android.preference.Preference;
6 | import android.preference.PreferenceActivity;
7 | import android.support.annotation.LayoutRes;
8 | import android.support.annotation.Nullable;
9 | import android.support.v7.app.ActionBar;
10 | import android.support.v7.app.AlertDialog;
11 | import android.support.v7.app.AppCompatDelegate;
12 | import android.support.v7.widget.Toolbar;
13 | import android.view.MenuInflater;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.webkit.WebView;
18 |
19 | import com.frozendevs.cache.cleaner.R;
20 |
21 | public class SettingsActivity extends PreferenceActivity {
22 |
23 | private final static String ACTION_SETTINGS_ABOUT = "com.frozendevs.cache.cleaner.SETTINGS_ABOUT";
24 |
25 | private AppCompatDelegate mDelegate;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | getDelegate().installViewFactory();
30 | getDelegate().onCreate(savedInstanceState);
31 |
32 | super.onCreate(savedInstanceState);
33 |
34 | String action = getIntent().getAction();
35 |
36 | if (action != null && action.equals(ACTION_SETTINGS_ABOUT)) {
37 | addPreferencesFromResource(R.xml.settings_about);
38 |
39 | String versionName;
40 | try {
41 | versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
42 | } catch (Exception e) {
43 | versionName = getString(R.string.version_number_unknown);
44 | }
45 | findPreference("version").setSummary(versionName);
46 |
47 | findPreference("licences").setOnPreferenceClickListener(
48 | new Preference.OnPreferenceClickListener() {
49 | @Override
50 | public boolean onPreferenceClick(Preference preference) {
51 | WebView webView = new WebView(getApplicationContext());
52 | webView.loadUrl("file:///android_asset/html/licenses.html");
53 |
54 | AlertDialog dialog = new AlertDialog.Builder(
55 | SettingsActivity.this).create();
56 | dialog.setTitle(R.string.open_source_licences);
57 | dialog.setView(webView);
58 | dialog.show();
59 |
60 | return true;
61 | }
62 | });
63 | } else {
64 | addPreferencesFromResource(R.xml.settings);
65 | }
66 | }
67 |
68 | @Override
69 | protected void onPostCreate(Bundle savedInstanceState) {
70 | super.onPostCreate(savedInstanceState);
71 |
72 | getDelegate().onPostCreate(savedInstanceState);
73 | }
74 |
75 | public ActionBar getSupportActionBar() {
76 | return getDelegate().getSupportActionBar();
77 | }
78 |
79 | public void setSupportActionBar(@Nullable Toolbar toolbar) {
80 | getDelegate().setSupportActionBar(toolbar);
81 | }
82 |
83 | @Override
84 | public MenuInflater getMenuInflater() {
85 | return getDelegate().getMenuInflater();
86 | }
87 |
88 | @Override
89 | public void setContentView(@LayoutRes int layoutResID) {
90 | getDelegate().setContentView(layoutResID);
91 | }
92 |
93 | @Override
94 | public void setContentView(View view) {
95 | getDelegate().setContentView(view);
96 | }
97 |
98 | @Override
99 | public void setContentView(View view, ViewGroup.LayoutParams params) {
100 | getDelegate().setContentView(view, params);
101 | }
102 |
103 | @Override
104 | public void addContentView(View view, ViewGroup.LayoutParams params) {
105 | getDelegate().addContentView(view, params);
106 | }
107 |
108 | @Override
109 | protected void onPostResume() {
110 | super.onPostResume();
111 |
112 | getDelegate().onPostResume();
113 | }
114 |
115 | @Override
116 | protected void onTitleChanged(CharSequence title, int color) {
117 | super.onTitleChanged(title, color);
118 |
119 | getDelegate().setTitle(title);
120 | }
121 |
122 | @Override
123 | public void onConfigurationChanged(Configuration newConfig) {
124 | super.onConfigurationChanged(newConfig);
125 |
126 | getDelegate().onConfigurationChanged(newConfig);
127 | }
128 |
129 | @Override
130 | protected void onStop() {
131 | super.onStop();
132 |
133 | getDelegate().onStop();
134 | }
135 |
136 | @Override
137 | protected void onDestroy() {
138 | super.onDestroy();
139 |
140 | getDelegate().onDestroy();
141 | }
142 |
143 | public void invalidateOptionsMenu() {
144 | getDelegate().invalidateOptionsMenu();
145 | }
146 |
147 | private AppCompatDelegate getDelegate() {
148 | if (mDelegate == null) {
149 | mDelegate = AppCompatDelegate.create(this, null);
150 | }
151 |
152 | return mDelegate;
153 | }
154 |
155 | @Override
156 | public boolean onOptionsItemSelected(MenuItem item) {
157 | switch (item.getItemId()) {
158 | case android.R.id.home:
159 | finish();
160 | return true;
161 | }
162 |
163 | return super.onOptionsItemSelected(item);
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/fragment/CleanerFragment.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.fragment;
2 |
3 | import android.Manifest;
4 | import android.app.ProgressDialog;
5 | import android.content.ComponentName;
6 | import android.content.Context;
7 | import android.content.DialogInterface;
8 | import android.content.Intent;
9 | import android.content.ServiceConnection;
10 | import android.content.SharedPreferences;
11 | import android.content.pm.PackageManager;
12 | import android.os.Build;
13 | import android.os.Bundle;
14 | import android.os.Environment;
15 | import android.os.IBinder;
16 | import android.os.StatFs;
17 | import android.preference.PreferenceManager;
18 | import android.support.annotation.NonNull;
19 | import android.support.v4.app.Fragment;
20 | import android.support.v4.view.MenuItemCompat;
21 | import android.support.v4.view.ViewCompat;
22 | import android.support.v7.app.AlertDialog;
23 | import android.support.v7.widget.LinearLayoutManager;
24 | import android.support.v7.widget.SearchView;
25 | import android.view.KeyEvent;
26 | import android.view.LayoutInflater;
27 | import android.view.Menu;
28 | import android.view.MenuInflater;
29 | import android.view.MenuItem;
30 | import android.view.View;
31 | import android.view.ViewGroup;
32 | import android.view.animation.AnimationUtils;
33 | import android.widget.TextView;
34 | import android.widget.Toast;
35 |
36 | import com.frozendevs.cache.cleaner.R;
37 | import com.frozendevs.cache.cleaner.activity.SettingsActivity;
38 | import com.frozendevs.cache.cleaner.model.AppsListItem;
39 | import com.frozendevs.cache.cleaner.model.CleanerService;
40 | import com.frozendevs.cache.cleaner.model.adapter.AppsListAdapter;
41 | import com.frozendevs.cache.cleaner.widget.DividerDecoration;
42 | import com.frozendevs.cache.cleaner.widget.RecyclerView;
43 |
44 | import java.util.List;
45 |
46 | public class CleanerFragment extends Fragment implements CleanerService.OnActionListener {
47 |
48 | private static final int REQUEST_STORAGE = 0;
49 |
50 | private static final String[] PERMISSIONS_STORAGE = {
51 | Manifest.permission.WRITE_EXTERNAL_STORAGE
52 | };
53 |
54 | private CleanerService mCleanerService;
55 | private AppsListAdapter mAppsListAdapter;
56 | private TextView mEmptyView;
57 | private SharedPreferences mSharedPreferences;
58 | private ProgressDialog mProgressDialog;
59 | private View mProgressBar;
60 | private TextView mProgressBarText;
61 | private LinearLayoutManager mLayoutManager;
62 | private Menu mOptionsMenu;
63 |
64 | private boolean mAlreadyScanned = false;
65 | private boolean mAlreadyCleaned = false;
66 | private String mSearchQuery;
67 |
68 | private String mSortByKey;
69 | private String mCleanOnAppStartupKey;
70 | private String mExitAfterCleanKey;
71 |
72 | private ServiceConnection mServiceConnection = new ServiceConnection() {
73 | @Override
74 | public void onServiceConnected(ComponentName name, IBinder service) {
75 | mCleanerService = ((CleanerService.CleanerServiceBinder) service).getService();
76 | mCleanerService.setOnActionListener(CleanerFragment.this);
77 |
78 | updateStorageUsage();
79 |
80 | if (!mCleanerService.isCleaning() && !mCleanerService.isScanning()) {
81 | if (mSharedPreferences.getBoolean(mCleanOnAppStartupKey, false) &&
82 | !mAlreadyCleaned) {
83 | mAlreadyCleaned = true;
84 |
85 | cleanCache();
86 | } else if (!mAlreadyScanned) {
87 | mCleanerService.scanCache();
88 | }
89 | }
90 | }
91 |
92 | @Override
93 | public void onServiceDisconnected(ComponentName name) {
94 | mCleanerService.setOnActionListener(null);
95 | mCleanerService = null;
96 | }
97 | };
98 |
99 | @Override
100 | public void onCreate(Bundle savedInstanceState) {
101 | super.onCreate(savedInstanceState);
102 |
103 | setHasOptionsMenu(true);
104 | setRetainInstance(true);
105 |
106 | mSortByKey = getString(R.string.sort_by_key);
107 | mCleanOnAppStartupKey = getString(R.string.clean_on_app_startup_key);
108 | mExitAfterCleanKey = getString(R.string.exit_after_clean_key);
109 |
110 | mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
111 |
112 | mAppsListAdapter = new AppsListAdapter();
113 |
114 | mProgressDialog = new ProgressDialog(getActivity());
115 | mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
116 | mProgressDialog.setCanceledOnTouchOutside(false);
117 | mProgressDialog.setTitle(R.string.cleaning_cache);
118 | mProgressDialog.setMessage(getString(R.string.cleaning_in_progress));
119 | mProgressDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
120 | @Override
121 | public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
122 | return true;
123 | }
124 | });
125 |
126 | getActivity().getApplication().bindService(new Intent(getActivity(), CleanerService.class),
127 | mServiceConnection, Context.BIND_AUTO_CREATE);
128 | }
129 |
130 | @Override
131 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
132 | View rootView = inflater.inflate(R.layout.cleaner_fragment, container, false);
133 |
134 | mEmptyView = (TextView) rootView.findViewById(R.id.empty_view);
135 |
136 | mLayoutManager = new LinearLayoutManager(getActivity());
137 |
138 | RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
139 | recyclerView.setLayoutManager(mLayoutManager);
140 | recyclerView.setAdapter(mAppsListAdapter);
141 | recyclerView.setEmptyView(mEmptyView);
142 | recyclerView.addItemDecoration(new DividerDecoration(getActivity()));
143 |
144 | mProgressBar = rootView.findViewById(R.id.progressBar);
145 | mProgressBarText = (TextView) rootView.findViewById(R.id.progressBarText);
146 |
147 | return rootView;
148 | }
149 |
150 | @Override
151 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
152 | mOptionsMenu = menu;
153 |
154 | inflater.inflate(R.menu.main_menu, menu);
155 |
156 | final MenuItem searchItem = menu.findItem(R.id.action_search);
157 |
158 | final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
159 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
160 | @Override
161 | public boolean onQueryTextSubmit(String query) {
162 | mSearchQuery = query;
163 |
164 | searchView.clearFocus();
165 |
166 | return true;
167 | }
168 |
169 | @Override
170 | public boolean onQueryTextChange(String newText) {
171 | if (ViewCompat.isLaidOut(searchView) && mSearchQuery != null) {
172 | String oldText = mSearchQuery;
173 |
174 | mSearchQuery = newText;
175 |
176 | if (!oldText.equals(newText)) {
177 | mAppsListAdapter.sortAndFilter(getActivity(), getSortBy(), newText);
178 | }
179 | }
180 |
181 | return true;
182 | }
183 | });
184 |
185 | MenuItemCompat.setOnActionExpandListener(searchItem,
186 | new MenuItemCompat.OnActionExpandListener() {
187 | @Override
188 | public boolean onMenuItemActionExpand(MenuItem item) {
189 | if (mSearchQuery == null) {
190 | mSearchQuery = "";
191 | }
192 |
193 | mAppsListAdapter.setShowHeaderView(false);
194 |
195 | mEmptyView.setText(R.string.no_such_app);
196 |
197 | return true;
198 | }
199 |
200 | @Override
201 | public boolean onMenuItemActionCollapse(MenuItem item) {
202 | mSearchQuery = null;
203 |
204 | mAppsListAdapter.clearFilter();
205 |
206 | mAppsListAdapter.setShowHeaderView(true);
207 |
208 | if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
209 | mLayoutManager.scrollToPosition(0);
210 | }
211 |
212 | mEmptyView.setText(R.string.empty_cache);
213 |
214 | return true;
215 | }
216 | });
217 |
218 | if (mSearchQuery != null) {
219 | MenuItemCompat.expandActionView(searchItem);
220 |
221 | searchView.setQuery(mSearchQuery, false);
222 | }
223 |
224 | updateOptionsMenu();
225 |
226 | super.onCreateOptionsMenu(menu, inflater);
227 | }
228 |
229 | @Override
230 | public boolean onOptionsItemSelected(MenuItem item) {
231 | switch (item.getItemId()) {
232 | case R.id.action_clean:
233 | if (mCleanerService != null && !mCleanerService.isScanning() &&
234 | !mCleanerService.isCleaning() && mCleanerService.getCacheSize() > 0) {
235 | mAlreadyCleaned = false;
236 |
237 | cleanCache();
238 | }
239 | return true;
240 |
241 | case R.id.action_refresh:
242 | if (mCleanerService != null && !mCleanerService.isScanning() &&
243 | !mCleanerService.isCleaning()) {
244 | mCleanerService.scanCache();
245 | }
246 | return true;
247 |
248 | case R.id.action_settings:
249 | startActivity(new Intent(getActivity(), SettingsActivity.class));
250 | return true;
251 |
252 | case R.id.action_sort_by_app_name:
253 | setSortBy(AppsListAdapter.SortBy.APP_NAME);
254 | updateOptionsMenu();
255 | return true;
256 |
257 | case R.id.action_sort_by_cache_size:
258 | setSortBy(AppsListAdapter.SortBy.CACHE_SIZE);
259 | updateOptionsMenu();
260 | return true;
261 |
262 | }
263 |
264 | return super.onOptionsItemSelected(item);
265 | }
266 |
267 | @Override
268 | public void onPrepareOptionsMenu(Menu menu) {
269 | updateOptionsMenu();
270 | }
271 |
272 | @Override
273 | public void onDestroyOptionsMenu() {
274 | mOptionsMenu = null;
275 | }
276 |
277 | @Override
278 | public void onResume() {
279 | updateStorageUsage();
280 |
281 | updateOptionsMenu();
282 |
283 | if (mCleanerService != null) {
284 | if (mCleanerService.isScanning() && !isProgressBarVisible()) {
285 | showProgressBar(true);
286 | } else if (!mCleanerService.isScanning() && isProgressBarVisible()) {
287 | showProgressBar(false);
288 | }
289 |
290 | if (mCleanerService.isCleaning() && !mProgressDialog.isShowing()) {
291 | mProgressDialog.show();
292 | }
293 | }
294 |
295 | super.onResume();
296 | }
297 |
298 | @Override
299 | public void onPause() {
300 | if (mProgressDialog.isShowing()) {
301 | mProgressDialog.dismiss();
302 | }
303 |
304 | super.onPause();
305 | }
306 |
307 | @Override
308 | public void onDestroy() {
309 | getActivity().getApplication().unbindService(mServiceConnection);
310 |
311 | super.onDestroy();
312 | }
313 |
314 | private void updateOptionsMenu() {
315 | if (mOptionsMenu != null) {
316 | mOptionsMenu.findItem(R.id.action_sort_by_app_name).setVisible(
317 | getSortBy() == AppsListAdapter.SortBy.CACHE_SIZE);
318 | mOptionsMenu.findItem(R.id.action_sort_by_cache_size).setVisible(
319 | getSortBy() == AppsListAdapter.SortBy.APP_NAME);
320 | }
321 | }
322 |
323 | private void updateStorageUsage() {
324 | if (mAppsListAdapter != null) {
325 | StatFs stat = new StatFs(Environment.getDataDirectory().getAbsolutePath());
326 |
327 | long totalMemory = (long) stat.getBlockCount() * (long) stat.getBlockSize();
328 | long medMemory = mCleanerService != null ? mCleanerService.getCacheSize() : 0;
329 | long lowMemory = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
330 |
331 | if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
332 | !Environment.isExternalStorageEmulated()) {
333 | stat = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath());
334 |
335 | totalMemory += (long) stat.getBlockCount() * (long) stat.getBlockSize();
336 | lowMemory += (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
337 | }
338 |
339 | long highMemory = totalMemory - medMemory - lowMemory;
340 |
341 | mAppsListAdapter.updateStorageUsage(totalMemory, lowMemory, medMemory, highMemory);
342 | }
343 | }
344 |
345 | private AppsListAdapter.SortBy getSortBy() {
346 | try {
347 | return AppsListAdapter.SortBy.valueOf(mSharedPreferences.getString(mSortByKey,
348 | AppsListAdapter.SortBy.CACHE_SIZE.toString()));
349 | } catch (ClassCastException e) {
350 | return AppsListAdapter.SortBy.CACHE_SIZE;
351 | }
352 | }
353 |
354 | private void setSortBy(AppsListAdapter.SortBy sortBy) {
355 | mSharedPreferences.edit().putString(mSortByKey, sortBy.toString()).apply();
356 |
357 | if (mCleanerService != null && !mCleanerService.isScanning() &&
358 | !mCleanerService.isCleaning()) {
359 | mAppsListAdapter.sortAndFilter(getActivity(), sortBy, mSearchQuery);
360 | }
361 | }
362 |
363 | private boolean isProgressBarVisible() {
364 | return mProgressBar.getVisibility() == View.VISIBLE;
365 | }
366 |
367 | private void showProgressBar(boolean show) {
368 | if (show) {
369 | mProgressBar.setVisibility(View.VISIBLE);
370 | } else {
371 | mProgressBar.startAnimation(AnimationUtils.loadAnimation(
372 | getActivity(), android.R.anim.fade_out));
373 | mProgressBar.setVisibility(View.GONE);
374 | }
375 | }
376 |
377 | private void showStorageRationale() {
378 | AlertDialog dialog = new AlertDialog.Builder(getActivity()).create();
379 | dialog.setTitle(R.string.rationale_title);
380 | dialog.setMessage(getString(R.string.rationale_storage));
381 | dialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(android.R.string.ok),
382 | new DialogInterface.OnClickListener() {
383 | @Override
384 | public void onClick(DialogInterface dialog, int which) {
385 | }
386 | });
387 | dialog.show();
388 | }
389 |
390 | private void cleanCache() {
391 | if (!CleanerService.canCleanExternalCache(getActivity())) {
392 | if (shouldShowRequestPermissionRationale(PERMISSIONS_STORAGE[0])) {
393 | showStorageRationale();
394 | } else {
395 | requestPermissions(PERMISSIONS_STORAGE, REQUEST_STORAGE);
396 | }
397 | } else {
398 | mCleanerService.cleanCache();
399 | }
400 | }
401 |
402 | @Override
403 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
404 | @NonNull int[] grantResults) {
405 | if (requestCode == REQUEST_STORAGE) {
406 | if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
407 | mCleanerService.cleanCache();
408 | } else {
409 | showStorageRationale();
410 | }
411 | } else {
412 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
413 | }
414 | }
415 |
416 | @Override
417 | public void onScanStarted(Context context) {
418 | if (isAdded()) {
419 | if (mProgressDialog.isShowing()) {
420 | mProgressDialog.dismiss();
421 | }
422 |
423 | mProgressBarText.setText(R.string.scanning);
424 | showProgressBar(true);
425 | }
426 | }
427 |
428 | @Override
429 | public void onScanProgressUpdated(Context context, int current, int max) {
430 | if (isAdded()) {
431 | mProgressBarText.setText(getString(R.string.scanning_m_of_n, current, max));
432 | }
433 | }
434 |
435 | @Override
436 | public void onScanCompleted(Context context, List apps) {
437 | mAppsListAdapter.setItems(getActivity(), apps, getSortBy(), mSearchQuery);
438 |
439 | if (isAdded()) {
440 | updateStorageUsage();
441 |
442 | showProgressBar(false);
443 | }
444 |
445 | mAlreadyScanned = true;
446 | }
447 |
448 | @Override
449 | public void onCleanStarted(Context context) {
450 | if (isAdded()) {
451 | if (isProgressBarVisible()) {
452 | showProgressBar(false);
453 | }
454 |
455 | if (!getActivity().isFinishing()) {
456 | mProgressDialog.show();
457 | }
458 | }
459 | }
460 |
461 | @Override
462 | public void onCleanCompleted(Context context, boolean succeeded) {
463 | if (succeeded) {
464 | mAppsListAdapter.trashItems();
465 | }
466 |
467 | if (isAdded()) {
468 | updateStorageUsage();
469 |
470 | if (mProgressDialog.isShowing()) {
471 | mProgressDialog.dismiss();
472 | }
473 | }
474 |
475 | Toast.makeText(context, succeeded ? R.string.cleaned : R.string.toast_could_not_clean,
476 | Toast.LENGTH_LONG).show();
477 |
478 | if (succeeded && getActivity() != null && !mAlreadyCleaned &&
479 | mSharedPreferences.getBoolean(mExitAfterCleanKey, false)) {
480 | getActivity().finish();
481 | }
482 | }
483 | }
484 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/model/AppsListItem.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.model;
2 |
3 | import android.graphics.drawable.Drawable;
4 |
5 | public class AppsListItem {
6 |
7 | private long mCacheSize;
8 | private String mPackageName, mApplicationName;
9 | private Drawable mIcon;
10 |
11 | public AppsListItem(String packageName, String applicationName, Drawable icon, long cacheSize) {
12 | mCacheSize = cacheSize;
13 | mPackageName = packageName;
14 | mApplicationName = applicationName;
15 | mIcon = icon;
16 | }
17 |
18 | public Drawable getApplicationIcon() {
19 | return mIcon;
20 | }
21 |
22 | public String getApplicationName() {
23 | return mApplicationName;
24 | }
25 |
26 | public long getCacheSize() {
27 | return mCacheSize;
28 | }
29 |
30 | public String getPackageName() {
31 | return mPackageName;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/model/BroadcastReceiver.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.model;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.preference.PreferenceManager;
7 |
8 | import com.frozendevs.cache.cleaner.R;
9 |
10 | public class BroadcastReceiver extends android.content.BroadcastReceiver {
11 |
12 | @Override
13 | public void onReceive(Context context, Intent intent) {
14 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
15 |
16 | String action = intent.getAction();
17 |
18 | if (action != null) {
19 | if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
20 | if (sharedPreferences.getBoolean(context.getString(
21 | R.string.clean_on_system_startup_key), false)) {
22 | Intent serviceIntent = new Intent(context, CleanerService.class);
23 | serviceIntent.setAction(CleanerService.ACTION_CLEAN_AND_EXIT);
24 | context.startService(serviceIntent);
25 | }
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/model/CleanerService.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.model;
2 |
3 | import android.Manifest;
4 | import android.app.Service;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.pm.ApplicationInfo;
8 | import android.content.pm.IPackageDataObserver;
9 | import android.content.pm.IPackageStatsObserver;
10 | import android.content.pm.PackageManager;
11 | import android.content.pm.PackageStats;
12 | import android.os.AsyncTask;
13 | import android.os.Binder;
14 | import android.os.Build;
15 | import android.os.Environment;
16 | import android.os.Handler;
17 | import android.os.IBinder;
18 | import android.os.RemoteException;
19 | import android.os.StatFs;
20 | import android.support.v4.content.ContextCompat;
21 | import android.util.Log;
22 | import android.widget.Toast;
23 |
24 | import com.frozendevs.cache.cleaner.R;
25 |
26 | import java.io.File;
27 | import java.lang.reflect.InvocationTargetException;
28 | import java.lang.reflect.Method;
29 | import java.util.ArrayList;
30 | import java.util.List;
31 | import java.util.concurrent.CountDownLatch;
32 |
33 | public class CleanerService extends Service {
34 |
35 | public static final String ACTION_CLEAN_AND_EXIT = "com.frozendevs.cache.cleaner.CLEAN_AND_EXIT";
36 |
37 | private static final String TAG = "CleanerService";
38 |
39 | private Method mGetPackageSizeInfoMethod, mFreeStorageAndNotifyMethod;
40 | private OnActionListener mOnActionListener;
41 | private boolean mIsScanning = false;
42 | private boolean mIsCleaning = false;
43 | private long mCacheSize = 0;
44 |
45 | public interface OnActionListener {
46 | void onScanStarted(Context context);
47 |
48 | void onScanProgressUpdated(Context context, int current, int max);
49 |
50 | void onScanCompleted(Context context, List apps);
51 |
52 | void onCleanStarted(Context context);
53 |
54 | void onCleanCompleted(Context context, boolean succeeded);
55 | }
56 |
57 | public class CleanerServiceBinder extends Binder {
58 |
59 | public CleanerService getService() {
60 | return CleanerService.this;
61 | }
62 | }
63 |
64 | private CleanerServiceBinder mBinder = new CleanerServiceBinder();
65 |
66 | private class TaskScan extends AsyncTask> {
67 |
68 | private int mAppCount = 0;
69 |
70 | @Override
71 | protected void onPreExecute() {
72 | if (mOnActionListener != null) {
73 | mOnActionListener.onScanStarted(CleanerService.this);
74 | }
75 | }
76 |
77 | @Override
78 | protected List doInBackground(Void... params) {
79 | mCacheSize = 0;
80 |
81 | final List packages = getPackageManager().getInstalledApplications(
82 | PackageManager.GET_META_DATA);
83 |
84 | publishProgress(0, packages.size());
85 |
86 | final CountDownLatch countDownLatch = new CountDownLatch(packages.size());
87 |
88 | final List apps = new ArrayList<>();
89 |
90 | try {
91 | for (ApplicationInfo pkg : packages) {
92 | mGetPackageSizeInfoMethod.invoke(getPackageManager(), pkg.packageName,
93 | new IPackageStatsObserver.Stub() {
94 |
95 | @Override
96 | public void onGetStatsCompleted(PackageStats pStats,
97 | boolean succeeded)
98 | throws RemoteException {
99 | synchronized (apps) {
100 | publishProgress(++mAppCount, packages.size());
101 |
102 | mCacheSize += addPackage(apps, pStats, succeeded);
103 | }
104 |
105 | synchronized (countDownLatch) {
106 | countDownLatch.countDown();
107 | }
108 | }
109 | }
110 | );
111 | }
112 |
113 | countDownLatch.await();
114 | } catch (InvocationTargetException | InterruptedException | IllegalAccessException e) {
115 | e.printStackTrace();
116 | }
117 |
118 | return new ArrayList<>(apps);
119 | }
120 |
121 | @Override
122 | protected void onProgressUpdate(Integer... values) {
123 | if (mOnActionListener != null) {
124 | mOnActionListener.onScanProgressUpdated(CleanerService.this, values[0], values[1]);
125 | }
126 | }
127 |
128 | @Override
129 | protected void onPostExecute(List result) {
130 | if (mOnActionListener != null) {
131 | mOnActionListener.onScanCompleted(CleanerService.this, result);
132 | }
133 |
134 | mIsScanning = false;
135 | }
136 |
137 | private long addPackage(List apps, PackageStats pStats, boolean succeeded) {
138 | long cacheSize = 0;
139 |
140 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
141 | cacheSize += pStats.cacheSize;
142 | }
143 |
144 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
145 | cacheSize += pStats.externalCacheSize;
146 | }
147 |
148 | if (!succeeded || cacheSize <= 0) {
149 | return 0;
150 | }
151 |
152 | try {
153 | PackageManager packageManager = getPackageManager();
154 | ApplicationInfo info = packageManager.getApplicationInfo(pStats.packageName,
155 | PackageManager.GET_META_DATA);
156 |
157 | apps.add(new AppsListItem(pStats.packageName,
158 | packageManager.getApplicationLabel(info).toString(),
159 | packageManager.getApplicationIcon(pStats.packageName),
160 | cacheSize));
161 | } catch (PackageManager.NameNotFoundException e) {
162 | e.printStackTrace();
163 | }
164 |
165 | return cacheSize;
166 | }
167 | }
168 |
169 | private class TaskClean extends AsyncTask {
170 |
171 | @Override
172 | protected void onPreExecute() {
173 | if (mOnActionListener != null) {
174 | mOnActionListener.onCleanStarted(CleanerService.this);
175 | }
176 | }
177 |
178 | @Override
179 | protected Boolean doInBackground(Void... params) {
180 | final CountDownLatch countDownLatch = new CountDownLatch(1);
181 |
182 | StatFs stat = new StatFs(Environment.getDataDirectory().getAbsolutePath());
183 |
184 | try {
185 | if (canCleanInternalCache(CleanerService.this)) {
186 | mFreeStorageAndNotifyMethod.invoke(getPackageManager(),
187 | (long) stat.getBlockCount() * (long) stat.getBlockSize(),
188 | new IPackageDataObserver.Stub() {
189 | @Override
190 | public void onRemoveCompleted(String packageName, boolean succeeded)
191 | throws RemoteException {
192 | countDownLatch.countDown();
193 | }
194 | }
195 | );
196 | } else {
197 | countDownLatch.countDown();
198 | }
199 |
200 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
201 | if (isExternalStorageWritable()) {
202 | final File externalDataDirectory = new File(Environment
203 | .getExternalStorageDirectory().getAbsolutePath() + "/Android/data");
204 |
205 | final String externalCachePath = externalDataDirectory.getAbsolutePath() +
206 | "/%s/cache";
207 |
208 | if (externalDataDirectory.isDirectory()) {
209 | final File[] files = externalDataDirectory.listFiles();
210 |
211 | for (File file : files) {
212 | if (!deleteDirectory(new File(String.format(externalCachePath,
213 | file.getName())), true)) {
214 | Log.e(TAG, "External storage suddenly becomes unavailable");
215 |
216 | return false;
217 | }
218 | }
219 | } else {
220 | Log.e(TAG, "External data directory is not a directory!");
221 | }
222 | } else {
223 | Log.d(TAG, "External storage is unavailable");
224 | }
225 | }
226 |
227 | countDownLatch.await();
228 | } catch (InterruptedException | IllegalAccessException e) {
229 | e.printStackTrace();
230 | } catch (InvocationTargetException e) {
231 | return false;
232 | }
233 |
234 | return true;
235 | }
236 |
237 | @Override
238 | protected void onPostExecute(Boolean result) {
239 | if (result) {
240 | mCacheSize = 0;
241 | }
242 |
243 | if (mOnActionListener != null) {
244 | mOnActionListener.onCleanCompleted(CleanerService.this, result);
245 | }
246 |
247 | mIsCleaning = false;
248 | }
249 |
250 | private boolean deleteDirectory(File file, boolean directoryOnly) {
251 | if (!isExternalStorageWritable()) {
252 | return false;
253 | }
254 |
255 | if (file == null || !file.exists() || (directoryOnly && !file.isDirectory())) {
256 | return true;
257 | }
258 |
259 | if (file.isDirectory()) {
260 | final File[] children = file.listFiles();
261 |
262 | if (children != null) {
263 | for (File child : children) {
264 | if (!deleteDirectory(child, false)) {
265 | return false;
266 | }
267 | }
268 | }
269 | }
270 |
271 | file.delete();
272 |
273 | return true;
274 | }
275 |
276 | private boolean isExternalStorageWritable() {
277 | return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
278 | }
279 | }
280 |
281 | @Override
282 | public IBinder onBind(Intent intent) {
283 | return mBinder;
284 | }
285 |
286 | @Override
287 | public void onCreate() {
288 | try {
289 | mGetPackageSizeInfoMethod = getPackageManager().getClass().getMethod(
290 | "getPackageSizeInfo", String.class, IPackageStatsObserver.class);
291 |
292 | mFreeStorageAndNotifyMethod = getPackageManager().getClass().getMethod(
293 | "freeStorageAndNotify", long.class, IPackageDataObserver.class);
294 | } catch (NoSuchMethodException e) {
295 | e.printStackTrace();
296 | }
297 | }
298 |
299 | @Override
300 | public int onStartCommand(Intent intent, int flags, int startId) {
301 | String action = null;
302 |
303 | if (intent != null) {
304 | action = intent.getAction();
305 | }
306 |
307 | if (action == null) {
308 | return START_NOT_STICKY;
309 | }
310 |
311 | if (action.equals(ACTION_CLEAN_AND_EXIT)) {
312 | if (!canCleanExternalCache(this)) {
313 | Log.e(TAG, "Could not clean the cache: Insufficient permissions");
314 |
315 | Toast.makeText(this, getString(R.string.toast_could_not_clean_reason,
316 | getString(R.string.rationale_title)), Toast.LENGTH_LONG).show();
317 |
318 | return START_NOT_STICKY;
319 | }
320 |
321 | setOnActionListener(new OnActionListener() {
322 | @Override
323 | public void onScanStarted(Context context) {
324 | }
325 |
326 | @Override
327 | public void onScanProgressUpdated(Context context, int current, int max) {
328 | }
329 |
330 | @Override
331 | public void onScanCompleted(Context context, List apps) {
332 | }
333 |
334 | @Override
335 | public void onCleanStarted(Context context) {
336 | }
337 |
338 | @Override
339 | public void onCleanCompleted(Context context, boolean succeeded) {
340 | if (succeeded) {
341 | Log.d(TAG, "Cache cleaned");
342 | }
343 | else {
344 | Log.e(TAG, "Could not clean the cache");
345 | }
346 |
347 | Toast.makeText(CleanerService.this, succeeded ? R.string.cleaned :
348 | R.string.toast_could_not_clean, Toast.LENGTH_LONG).show();
349 |
350 | new Handler().postDelayed(new Runnable() {
351 | @Override
352 | public void run() {
353 | stopSelf();
354 | }
355 | }, 5000);
356 | }
357 | });
358 |
359 | cleanCache();
360 | }
361 |
362 | return START_NOT_STICKY;
363 | }
364 |
365 | public void scanCache() {
366 | mIsScanning = true;
367 |
368 | new TaskScan().execute();
369 | }
370 |
371 | public void cleanCache() {
372 | mIsCleaning = true;
373 |
374 | new TaskClean().execute();
375 | }
376 |
377 | public void setOnActionListener(OnActionListener listener) {
378 | mOnActionListener = listener;
379 | }
380 |
381 | public boolean isScanning() {
382 | return mIsScanning;
383 | }
384 |
385 | public boolean isCleaning() {
386 | return mIsCleaning;
387 | }
388 |
389 | public long getCacheSize() {
390 | return mCacheSize;
391 | }
392 |
393 | private static boolean hasPermission(Context context, String permission) {
394 | return ContextCompat.checkSelfPermission(context, permission) ==
395 | PackageManager.PERMISSION_GRANTED;
396 | }
397 |
398 | public static boolean canCleanInternalCache(Context context) {
399 | return hasPermission(context, Manifest.permission.CLEAR_APP_CACHE);
400 | }
401 |
402 | public static boolean canCleanExternalCache(Context context) {
403 | return hasPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
404 | }
405 | }
406 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/model/adapter/AppsListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.model.adapter;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.graphics.drawable.Drawable;
6 | import android.net.Uri;
7 | import android.support.v4.text.BidiFormatter;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.text.format.Formatter;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.ImageView;
14 | import android.widget.TextView;
15 |
16 | import com.android.settings.applications.LinearColorBar;
17 | import com.frozendevs.cache.cleaner.R;
18 | import com.frozendevs.cache.cleaner.model.AppsListItem;
19 |
20 | import java.util.ArrayList;
21 | import java.util.Collections;
22 | import java.util.Comparator;
23 | import java.util.List;
24 | import java.util.Locale;
25 |
26 | public class AppsListAdapter extends RecyclerView.Adapter {
27 |
28 | public enum SortBy {
29 | APP_NAME,
30 | CACHE_SIZE
31 | }
32 |
33 | public static final int VIEW_TYPE_HEADER = 0;
34 | public static final int VIEW_TYPE_ITEM = 1;
35 |
36 | private List mItems = new ArrayList<>();
37 | private List mFilteredItems = new ArrayList<>();
38 | private SortBy mLastSortBy;
39 | private boolean mShowHeaderView = true;
40 |
41 | private long mTotalMemory, mLowMemory, mMedMemory, mHighMemory;
42 |
43 | public static class ItemViewHolder extends RecyclerView.ViewHolder implements
44 | View.OnClickListener {
45 | private ImageView mIcon;
46 | private TextView mName, mSize;
47 | private String mPackageName;
48 |
49 | public ItemViewHolder(View itemView) {
50 | super(itemView);
51 |
52 | mIcon = (ImageView) itemView.findViewById(R.id.app_icon);
53 | mName = (TextView) itemView.findViewById(R.id.app_name);
54 | mSize = (TextView) itemView.findViewById(R.id.app_size);
55 |
56 | itemView.setOnClickListener(this);
57 | }
58 |
59 | public void setIcon(Drawable drawable) {
60 | mIcon.setImageDrawable(drawable);
61 | }
62 |
63 | public void setName(String name) {
64 | mName.setText(name);
65 | }
66 |
67 | public void setPackageName(String packageName) {
68 | mPackageName = packageName;
69 | }
70 |
71 | public void setSize(long size) {
72 | mSize.setText(Formatter.formatShortFileSize(mSize.getContext(), size));
73 | }
74 |
75 | @Override
76 | public void onClick(View view) {
77 | if (mPackageName != null) {
78 | Intent intent = new Intent();
79 | intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
80 | intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
81 | intent.setData(Uri.parse("package:" + mPackageName));
82 |
83 | view.getContext().startActivity(intent);
84 | }
85 | }
86 | }
87 |
88 | public static class HeaderViewHolder extends RecyclerView.ViewHolder {
89 | private LinearColorBar mColorBar;
90 | private TextView mSystemSizeText;
91 | private TextView mCacheSizeText;
92 | private TextView mFreeSizeText;
93 |
94 | public HeaderViewHolder(View itemView) {
95 | super(itemView);
96 |
97 | mColorBar = (LinearColorBar) itemView.findViewById(R.id.color_bar);
98 | mColorBar.setColors(itemView.getResources().getColor(R.color.apps_list_system_memory),
99 | itemView.getResources().getColor(R.color.apps_list_cache_memory),
100 | itemView.getResources().getColor(R.color.apps_list_free_memory));
101 | mSystemSizeText = (TextView) itemView.findViewById(R.id.systemSize);
102 | mCacheSizeText = (TextView) itemView.findViewById(R.id.cacheSize);
103 | mFreeSizeText = (TextView) itemView.findViewById(R.id.freeSize);
104 | }
105 |
106 | public void updateStorageUsage(long totalMemory, long lowMemory, long medMemory,
107 | long highMemory) {
108 | Context context = mColorBar.getContext();
109 |
110 | BidiFormatter bidiFormatter = BidiFormatter.getInstance();
111 |
112 | String sizeStr = bidiFormatter.unicodeWrap(
113 | Formatter.formatShortFileSize(context, lowMemory));
114 | mFreeSizeText.setText(context.getString(R.string.apps_list_header_memory, sizeStr));
115 |
116 | sizeStr = bidiFormatter.unicodeWrap(
117 | Formatter.formatShortFileSize(context, medMemory));
118 | mCacheSizeText.setText(context.getString(R.string.apps_list_header_memory, sizeStr));
119 |
120 | sizeStr = bidiFormatter.unicodeWrap(
121 | Formatter.formatShortFileSize(context, highMemory));
122 | mSystemSizeText.setText(context.getString(R.string.apps_list_header_memory, sizeStr));
123 |
124 | mColorBar.setRatios((float) highMemory / (float) totalMemory,
125 | (float) medMemory / (float) totalMemory,
126 | (float) lowMemory / (float) totalMemory);
127 | }
128 | }
129 |
130 | public AppsListAdapter() {
131 | setHasStableIds(true);
132 | }
133 |
134 | @Override
135 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
136 | switch (viewType) {
137 | case VIEW_TYPE_HEADER:
138 | return new HeaderViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(
139 | R.layout.apps_list_header, viewGroup, false));
140 |
141 | case VIEW_TYPE_ITEM:
142 | return new ItemViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(
143 | R.layout.list_item, viewGroup, false));
144 | }
145 |
146 | return null;
147 | }
148 |
149 | @Override
150 | public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
151 | if (viewHolder instanceof ItemViewHolder) {
152 | AppsListItem item = mFilteredItems.get(position);
153 |
154 | ((ItemViewHolder) viewHolder).setIcon(item.getApplicationIcon());
155 | ((ItemViewHolder) viewHolder).setName(item.getApplicationName());
156 | ((ItemViewHolder) viewHolder).setPackageName(item.getPackageName());
157 | ((ItemViewHolder) viewHolder).setSize(item.getCacheSize());
158 | } else if (viewHolder instanceof HeaderViewHolder) {
159 | ((HeaderViewHolder) viewHolder).updateStorageUsage(mTotalMemory, mLowMemory,
160 | mMedMemory, mHighMemory);
161 | }
162 | }
163 |
164 | @Override
165 | public long getItemId(int i) {
166 | AppsListItem item = mFilteredItems.get(i);
167 |
168 | return item != null ? item.hashCode() : 0;
169 | }
170 |
171 | @Override
172 | public int getItemCount() {
173 | return mFilteredItems.size();
174 | }
175 |
176 | private void insertHeaderView(List items) {
177 | if (mShowHeaderView && items.size() > 0) {
178 | items.add(0, null);
179 |
180 | notifyItemInserted(0);
181 | }
182 | }
183 |
184 | public void setItems(Context context, List items, SortBy sortBy, String filter) {
185 | mItems = items;
186 |
187 | mLastSortBy = null;
188 |
189 | if (mItems.size() > 0) {
190 | sortAndFilter(context, sortBy, filter);
191 | } else {
192 | mFilteredItems = new ArrayList<>(mItems);
193 |
194 | insertHeaderView(mFilteredItems);
195 |
196 | notifyDataSetChanged();
197 | }
198 | }
199 |
200 | public void sortAndFilter(Context context, final SortBy sortBy, String filter) {
201 | if (sortBy != mLastSortBy) {
202 | mLastSortBy = sortBy;
203 |
204 | ArrayList items = new ArrayList<>(mItems);
205 |
206 | Collections.sort(items, new Comparator() {
207 | @Override
208 | public int compare(AppsListItem lhs, AppsListItem rhs) {
209 | switch (sortBy) {
210 | case APP_NAME:
211 | return lhs.getApplicationName().compareToIgnoreCase(
212 | rhs.getApplicationName());
213 |
214 | case CACHE_SIZE:
215 | return (int) (rhs.getCacheSize() - lhs.getCacheSize());
216 | }
217 |
218 | return 0;
219 | }
220 | });
221 |
222 | mItems = items;
223 | }
224 |
225 | if (filter != null && !filter.equals("")) {
226 | List filteredItems = new ArrayList<>();
227 |
228 | Locale current;
229 |
230 | try {
231 | current = context.getResources().getConfiguration().locale;
232 | } catch (NullPointerException e) {
233 | current = Locale.getDefault();
234 | }
235 |
236 | for (AppsListItem item : mItems) {
237 | if (item.getApplicationName().toLowerCase(current).contains(
238 | filter.toLowerCase(current))) {
239 | filteredItems.add(item);
240 | }
241 | }
242 |
243 | mFilteredItems = filteredItems;
244 |
245 | insertHeaderView(mFilteredItems);
246 | } else {
247 | mFilteredItems = new ArrayList<>(mItems);
248 |
249 | insertHeaderView(mFilteredItems);
250 | }
251 |
252 | notifyDataSetChanged();
253 | }
254 |
255 | public void clearFilter() {
256 | mFilteredItems = new ArrayList<>(mItems);
257 |
258 | insertHeaderView(mFilteredItems);
259 |
260 | notifyDataSetChanged();
261 | }
262 |
263 | public void updateStorageUsage(long totalMemory, long lowMemory, long medMemory,
264 | long highMemory) {
265 | mTotalMemory = totalMemory;
266 | mLowMemory = lowMemory;
267 | mMedMemory = medMemory;
268 | mHighMemory = highMemory;
269 |
270 | notifyDataSetChanged();
271 | }
272 |
273 | @Override
274 | public int getItemViewType(int position) {
275 | return mFilteredItems.get(position) == null ? VIEW_TYPE_HEADER : VIEW_TYPE_ITEM;
276 | }
277 |
278 | public void setShowHeaderView(boolean show) {
279 | boolean oldShow = mShowHeaderView;
280 |
281 | mShowHeaderView = show;
282 |
283 | if (show && !oldShow) {
284 | insertHeaderView(mFilteredItems);
285 | } else if (!show && oldShow && mFilteredItems.size() > 0) {
286 | mFilteredItems.remove(0);
287 |
288 | notifyItemRemoved(0);
289 | }
290 | }
291 |
292 | public void trashItems() {
293 | mItems = new ArrayList<>();
294 | mFilteredItems = new ArrayList<>();
295 |
296 | notifyDataSetChanged();
297 | }
298 | }
299 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/widget/DividerDecoration.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.drawable.Drawable;
7 | import android.support.v4.view.ViewCompat;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.View;
10 |
11 | import com.frozendevs.cache.cleaner.model.adapter.AppsListAdapter;
12 |
13 | public class DividerDecoration extends RecyclerView.ItemDecoration {
14 |
15 | private static final int[] ATTRS = {android.R.attr.listDivider};
16 |
17 | private Drawable mDivider;
18 |
19 | public DividerDecoration(Context context) {
20 | TypedArray typedArray = context.obtainStyledAttributes(ATTRS);
21 | mDivider = typedArray.getDrawable(0);
22 | typedArray.recycle();
23 | }
24 |
25 | @Override
26 | public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
27 | final int left = parent.getPaddingLeft();
28 | final int right = parent.getWidth() - parent.getPaddingRight();
29 |
30 | final int childCount = parent.getChildCount();
31 | for (int i = 0; i < childCount; i++) {
32 | final View child = parent.getChildAt(i);
33 |
34 | if (isDecorated(child, parent)) {
35 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
36 | .getLayoutParams();
37 | final int top = child.getBottom() + params.bottomMargin +
38 | (int) ViewCompat.getTranslationY(child);
39 | final int bottom = top + mDivider.getIntrinsicHeight();
40 | mDivider.setBounds(left, top, right, bottom);
41 | mDivider.draw(canvas);
42 | }
43 | }
44 | }
45 |
46 | private boolean isDecorated(View view, RecyclerView parent) {
47 | RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
48 |
49 | return !(holder instanceof AppsListAdapter.HeaderViewHolder &&
50 | holder.getItemViewType() == AppsListAdapter.VIEW_TYPE_HEADER);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/java/com/frozendevs/cache/cleaner/widget/RecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.frozendevs.cache.cleaner.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 |
7 | public class RecyclerView extends android.support.v7.widget.RecyclerView {
8 | private View mEmptyView;
9 |
10 | private final android.support.v7.widget.RecyclerView.AdapterDataObserver observer =
11 | new android.support.v7.widget.RecyclerView.AdapterDataObserver() {
12 | @Override
13 | public void onChanged() {
14 | checkIfEmpty();
15 | }
16 |
17 | @Override
18 | public void onItemRangeInserted(int positionStart, int itemCount) {
19 | checkIfEmpty();
20 | }
21 |
22 | @Override
23 | public void onItemRangeRemoved(int positionStart, int itemCount) {
24 | checkIfEmpty();
25 | }
26 | };
27 |
28 | public RecyclerView(Context context) {
29 | super(context);
30 | }
31 |
32 | public RecyclerView(Context context, AttributeSet attrs) {
33 | super(context, attrs);
34 | }
35 |
36 | public RecyclerView(Context context, AttributeSet attrs, int defStyle) {
37 | super(context, attrs, defStyle);
38 | }
39 |
40 | private void checkIfEmpty() {
41 | if (mEmptyView != null && getAdapter() != null) {
42 | final boolean emptyViewVisible = getAdapter().getItemCount() == 0;
43 |
44 | mEmptyView.setVisibility(emptyViewVisible ? VISIBLE : GONE);
45 |
46 | setVisibility(emptyViewVisible ? GONE : VISIBLE);
47 | }
48 | }
49 |
50 | @Override
51 | public void setAdapter(android.support.v7.widget.RecyclerView.Adapter adapter) {
52 | final RecyclerView.Adapter oldAdapter = getAdapter();
53 |
54 | if (oldAdapter != null) {
55 | oldAdapter.unregisterAdapterDataObserver(observer);
56 | }
57 |
58 | super.setAdapter(adapter);
59 |
60 | if (adapter != null) {
61 | adapter.registerAdapterDataObserver(observer);
62 | }
63 |
64 | checkIfEmpty();
65 | }
66 |
67 | public void setEmptyView(View emptyView) {
68 | mEmptyView = emptyView;
69 |
70 | checkIfEmpty();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-hdpi/ic_launcher_cache_cleaner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-hdpi/ic_launcher_cache_cleaner.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-hdpi/ic_menu_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-hdpi/ic_menu_delete.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-hdpi/ic_menu_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-hdpi/ic_menu_refresh.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-hdpi/ic_menu_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-hdpi/ic_menu_search.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-mdpi/ic_launcher_cache_cleaner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-mdpi/ic_launcher_cache_cleaner.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-mdpi/ic_menu_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-mdpi/ic_menu_delete.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-mdpi/ic_menu_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-mdpi/ic_menu_refresh.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-mdpi/ic_menu_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-mdpi/ic_menu_search.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xhdpi/ic_launcher_cache_cleaner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xhdpi/ic_launcher_cache_cleaner.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xhdpi/ic_menu_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xhdpi/ic_menu_delete.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xhdpi/ic_menu_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xhdpi/ic_menu_refresh.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xhdpi/ic_menu_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xhdpi/ic_menu_search.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xxhdpi/ic_launcher_cache_cleaner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xxhdpi/ic_launcher_cache_cleaner.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xxhdpi/ic_menu_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xxhdpi/ic_menu_delete.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xxhdpi/ic_menu_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xxhdpi/ic_menu_refresh.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xxhdpi/ic_menu_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xxhdpi/ic_menu_search.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xxxhdpi/ic_launcher_cache_cleaner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xxxhdpi/ic_launcher_cache_cleaner.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xxxhdpi/ic_menu_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xxxhdpi/ic_menu_delete.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xxxhdpi/ic_menu_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xxxhdpi/ic_menu_refresh.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable-xxxhdpi/ic_menu_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frozen-Developers/android-cache-cleaner/ea84ad2405fa0086e257340957a14cd9d9a5c019/CacheCleaner/src/main/res/drawable-xxxhdpi/ic_menu_search.png
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/drawable/dotted_line.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/layout/apps_list_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
21 |
22 |
27 |
28 |
33 |
34 |
41 |
42 |
47 |
48 |
59 |
60 |
61 |
62 |
71 |
72 |
73 |
74 |
75 |
76 |
80 |
81 |
88 |
89 |
94 |
95 |
106 |
107 |
108 |
109 |
118 |
119 |
120 |
121 |
122 |
123 |
127 |
128 |
135 |
136 |
141 |
142 |
153 |
154 |
155 |
156 |
165 |
166 |
167 |
168 |
169 |
170 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/layout/cleaner_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/layout/cleaner_fragment.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
23 |
24 |
31 |
32 |
33 |
34 |
42 |
43 |
47 |
48 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/layout/dotted_line.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/layout/list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
24 |
25 |
30 |
31 |
40 |
41 |
42 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
39 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Cache Cleaner
6 |
7 |
8 | Limpiar
9 | Reescanear
10 | Buscar
11 | Ordenar por nombre
12 | Ordenar por tamaño
13 | Ajustes
14 |
15 |
16 | Memoria del dispositivo
17 | En uso
18 | Caché
19 | Libre
20 | Uso de caché de la aplicación
21 | %1$s
22 |
23 |
24 | Caché vacío.
25 | No hay tal aplicación.
26 |
27 |
28 | Escaneando…
29 | Escaneando %1$d/%2$d
30 |
31 |
32 | Limpieza de caché
33 | Limpieza en progreso…
34 |
35 |
36 | Caché limpiado
37 | No se pudo limpiar caché
38 | No se pudo limpiar caché: %1$s
39 |
40 |
41 | Ajustes
42 | Preferencias principales
43 | Acerca de
44 |
45 |
46 | Limpiar al iniciar la aplicación
47 | Limpiar caché automáticamente al iniciar la aplicación
48 |
49 |
50 | Salir después de limpiar
51 | Salir cuando la limpieza esté completada
52 |
53 |
54 | Limpiar al iniciar el sistema
55 | Limpiar caché automaticamente al iniciar el sistena
56 |
57 |
58 | Acerca de Cache Cleaner
59 | Autor
60 | Número de versión
61 | Desconocido
62 | Licencias de código abierto
63 | Agradecimiento especial
64 | Diseño de icono y banner en Play Store
65 |
66 |
67 | Permisos insuficientes
68 | El permiso de almacenamiento es necesario para limpiar caché externo.
69 |
70 |
71 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Cache Cleaner
6 |
7 |
8 | Vider
9 | Rescanner
10 | Rechercher
11 | Trier par nom
12 | Trier par taille
13 | Paramètres
14 |
15 |
16 | Mémoire de l\'appareil
17 | Utilisée
18 | Cache
19 | Libérée
20 | Cache utilisé par application
21 | %1$s
22 |
23 |
24 | Le cache est vide.
25 | Pas de telle application.
26 |
27 |
28 | Scan…
29 | Scan %1$d/%2$d
30 |
31 |
32 | Nettoyage du cache
33 | Nettoyage en cours…
34 |
35 |
36 | Cache vidé
37 | Impossible de vider le cache
38 | Impossible de vider le cache : %1$s
39 |
40 |
41 | Paramètres
42 | Préférences principales
43 | À propos
44 |
45 |
46 | Vider au lancement de l\'application
47 | Vider automatiquement le cache au lancement de l\'application
48 |
49 |
50 | Quitter après nettoyage
51 | Quitter après que le bouton Vider soit pressé et que le nettoyage soit terminé
52 |
53 |
54 | Vider au lancement du système d\'exploitation
55 | Vider automatiquement le cache au lancement du système d\'exploitation
56 |
57 |
58 | À propos de Cache Cleaner
59 | Auteur
60 | Numéro de version
61 | Inconnu
62 | Licences open source
63 | Remerciements
64 | Icône et bannière du Play Store
65 |
66 |
67 | Autorisations insuffisantes
68 | L\'autorisation de stockage est nécessaire pour vider le cache externe.
69 |
70 |
71 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-hu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Gyorsítótár tisztító
6 |
7 |
8 | Tisztítás
9 | Átvizsgálás újra
10 | Keresés
11 | Rendezés név szerint
12 | Rendezés méret szerint
13 | Beállítások
14 |
15 |
16 | Eszközmemória
17 | Használt
18 | Gyorsítótár
19 | Szabad
20 | App gyorsítótár használat
21 | %1$s
22 |
23 |
24 | A gyorsítótár üres.
25 | Nincs ilyen alkalmazás.
26 |
27 |
28 | Átvizsgálás…
29 | Átvizsgálás %1$d/%2$d
30 |
31 |
32 | Gyorsítótár tisztítása
33 | Tisztítás folyamatban…
34 |
35 |
36 | Gyorsítótár kitisztítva
37 | A gyorsítótár nem tisztítható
38 | A gyorsítótár nem tisztítható: %1$s
39 |
40 |
41 | Beállítások
42 | Fő beállítások
43 | Névjegy
44 |
45 |
46 | Tisztítás az app indításakor
47 | Automatikus tisztítás az app indításakor
48 |
49 |
50 | Tisztítás után kilépés
51 | Kilépés, a Tisztítás gombra kattintás, és a tisztítás befejeződése után
52 |
53 |
54 | Tisztítás a rendszer indításakor
55 | Automatikus tisztítás a rendszer indításakor
56 |
57 |
58 | A gyorsítótár tisztító névjegye
59 | Szerzők
60 | Verziószám
61 | Ismeretlen
62 | Nyílt forráskódú licencek
63 | Külön köszönet
64 | Ikon és Play Store banner dizájn
65 |
66 |
67 | Elégtelen jogosultság
68 | Tárolás jogosultság szükséges a külső gyorsítótár tisztításához.
69 |
70 |
71 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Cache Cleaner
6 |
7 |
8 | クリーン
9 | 再スキャン
10 | 検索
11 | 名前で並び替え
12 | サイズで並び替え
13 | 設定
14 |
15 |
16 | デバイスのメモリ
17 | 使用
18 | キャッシュ
19 | 空き
20 | アプリキャッシュ使用状況
21 | %1$s
22 |
23 |
24 | キャッシュは空です。
25 | そのようなアプリケーションはありません。
26 |
27 |
28 | スキャン中…
29 | スキャン中 %1$d/%2$d
30 |
31 |
32 | キャッシュをクリーニング中
33 | クリーニングの実行中…
34 |
35 |
36 | キャッシュをクリーニングしました
37 | キャッシュをクリーニングできませんでした
38 | キャッシュをクリーニングできませんでした: %1$s
39 |
40 |
41 | 設定
42 | メイン設定
43 | アプリについて
44 |
45 |
46 | アプリ起動時にクリーニング
47 | アプリケーションの起動時に自動的にキャッシュをクリーニングします
48 |
49 |
50 | クリーンアップ後に終了
51 | クリーンボタンをクリックして、クリーンアップが完了した後に終了します
52 |
53 |
54 | システム起動時にクリーニング
55 | システムの起動時に自動的にキャッシュをクリーニングします
56 |
57 |
58 | Cache Cleaner について
59 | 作者
60 | バージョン番号
61 | 不明
62 | オープンソース ライセンス
63 | 謝辞
64 | アイコンと Play ストアのバナーデザイン
65 |
66 |
67 |
68 |
69 | アクセス許可が不足しています
70 | 外部キャッシュのクリーニングは、ストレージのアクセス許可が必要です。
71 |
72 |
73 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Cache Cleaner
6 |
7 |
8 | Limpar
9 | Analisar
10 | Procurar
11 | Ordenar por nome
12 | Ordenar por tamanho
13 | Definições
14 |
15 |
16 | Memória do dispositivo
17 | Em uso
18 | Cache
19 | Livre
20 | Utilização de cache
21 | %1$s
22 |
23 |
24 | Cache vazia
25 | Aplicação inexistente
26 |
27 |
28 | Análise…
29 | Analisando %1$d/%2$d
30 |
31 |
32 | Limpeza de cache
33 | Limpeza em curso…
34 |
35 |
36 | Cache apagada
37 | Não foi possível limpar a cache
38 | Não foi possível limpar a cache: %1$s
39 |
40 |
41 | Definições
42 | Definições principais
43 | Sobre
44 |
45 |
46 | Limpar ao iniciar a aplicação
47 | Limpar cache ao iniciar a aplicação
48 |
49 |
50 | Fechar após a limpeza
51 | Fechar aplicação depois de terminar a limpeza
52 |
53 |
54 | Limpar ao iniciar o sistema
55 | Limpar cache ao iniciar o sistema
56 |
57 |
58 | Sobre o Cache Cleaner
59 | Autor
60 | Número da versão
61 | Desconhecido
62 | Licenças Open Source
63 | Agradecimentos
64 | Criação do ícone e imagem na Play Store
65 |
66 |
67 | Permissões insuficientes
68 | Requer permissão de armazenamento para limpar a cache externa.
69 |
70 |
71 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-sk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Čistič medzipamäte
6 |
7 |
8 | Vyčistiť
9 | Reskenovať
10 | Hľadať
11 | Zoradiť podľa názvu
12 | Zoradiť podľa veľkosti
13 | Nastavenia
14 |
15 |
16 | Pamäť zariadenia
17 | Použité
18 | Medzipamäť
19 | Voľných
20 | Využitie medzipamäte
21 | %1$s
22 |
23 |
24 | Medzipamäť je prázdna.
25 | Žiadna podobná aplikácia.
26 |
27 |
28 | Skenovanie…
29 | Skenovanie %1$d/%2$d
30 |
31 |
32 | Čistenie medzipamäte
33 | Prebieha čistenie…
34 |
35 |
36 | Medzipamäť vyčistená
37 | Nemožno vyčistiť medzipamäť
38 | Nemožno vyčistiť medzipamäť: %1$s
39 |
40 |
41 | Nastavenia
42 | Hlavné nastavenia
43 | O aplikácii
44 |
45 |
46 | Vyčistiť pri štarte aplikácie
47 | Automaticky vyčistiť medzipamäť pri štarte aplikácie
48 |
49 |
50 | Odchod po vyčistení
51 | Odchod po slačení tlačidla Vyčistiť a ukončení čistenia
52 |
53 |
54 | Vyčistiť pri štarte systému
55 | Automaticky vyčistiť medzipamäť pri štarte systému
56 |
57 |
58 | O Čističi medzipamäte
59 | Autor
60 | Verzia
61 | Neznáma
62 | Open source licencie
63 | Špeciálne poďakovanie
64 | Dizajn ikony a transparentu pre Play obchod
65 |
66 |
67 | Nedostatočné povolenia
68 | Povolenie úložiska je potrebné na čistenie externej medzipamäte.
69 |
70 |
71 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-sr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Чистач кеша
6 |
7 |
8 | Очисти
9 | Поново скенирај
10 | Тражи
11 | Сортирај према имену
12 | Сортирај према величини
13 | Поставке
14 |
15 |
16 | Меморија уређаја
17 | У употреби
18 | Кеш
19 | Слободно
20 | Кеш који користе апликације
21 | %1$s
22 |
23 |
24 | Кеш је празан.
25 | Нема такве апликације.
26 |
27 |
28 | Скенирам…
29 | Скенирам %1$d/%2$d
30 |
31 |
32 | Чишћење кеша
33 | Чишћење је у току…
34 |
35 |
36 | Кеш је очишћен
37 | Нисам могао да очистим кеш
38 | Нисам могао да очистим кеш: %1$s
39 |
40 |
41 | Поставке
42 | Главно
43 | О програму
44 |
45 |
46 | Очисти по покретању
47 | Аутоматски очисти кеш по покретању апликације
48 |
49 |
50 | Изађи након чишћења
51 | Изађи након што се чишћење заврши
52 |
53 |
54 | Очисти по покретању система
55 | Аутоматски очисти кеш по покретању система
56 |
57 |
58 | О Чистачу кеша
59 | Програмер
60 | Издање
61 | Непознато
62 | Лиценце отвореног кôда
63 | Посебна захвала
64 | Дизајн иконе и банера Плеј продавнице
65 |
66 |
67 | Недовољно дозвола
68 | Дозвола за складиште је потребна за чишћење спољашњег складишта.
69 |
70 |
71 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 0dp
5 | 0dp
6 |
7 | 24dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 112dp
5 | 0dp
6 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values-sw720dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 64dp
5 | 0dp
6 |
7 | 80dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #ff263238
5 | #ff21272b
6 | #ff009688
7 |
8 | #ff384248
9 | #ff009587
10 | #ffced7db
11 |
12 | #8a000000
13 |
14 |
15 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 0dp
5 | 0dp
6 |
7 | 16dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Cache Cleaner
6 | Frozen Developers
7 |
8 |
9 | Clean
10 | Rescan
11 | Search
12 | Sort by name
13 | Sort by size
14 | Settings
15 |
16 |
17 | Device memory
18 | Used
19 | Cache
20 | Free
21 | App cache usage
22 | %1$s
23 |
24 |
25 | Cache is empty.
26 | No such application.
27 |
28 |
29 | Scanning…
30 | Scanning %1$d/%2$d
31 |
32 |
33 | Cleaning cache
34 | Cleaning in progress…
35 |
36 |
37 | Cache cleaned
38 | Could not clean the cache
39 | Could not clean the cache: %1$s
40 |
41 |
42 | Settings
43 | Main preferences
44 | About
45 |
46 |
47 | Clean on app startup
48 | Automatically clean cache on application startup
49 | clean_on_app_startup
50 |
51 |
52 | Exit after clean up
53 | Exit after Clean button is clicked and clean up is completed
54 | exit_after_clean
55 |
56 |
57 | Clean on system startup
58 | Automatically clean cache on system startup
59 | clean_on_device_startup
60 |
61 |
62 | About Cache Cleaner
63 | Author
64 | Version number
65 | Unknown
66 | Open source licences
67 | Special thanks
68 | Samuel\'s Graphics
69 | Icon and Play Store banner design
70 |
71 |
72 | sort_by
73 |
74 |
75 | Insufficient permissions
76 | Storage permission is needed to clean external cache.
77 |
78 |
79 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
14 |
15 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/values/urls.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https://github.com/Frozen-Developers
5 | https://www.facebook.com/samuelsgraphics
6 |
7 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/xml/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
12 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/CacheCleaner/src/main/res/xml/settings_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
18 |
21 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2015 Frozen Developers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Cache Cleaner [](https://travis-ci.org/Frozen-Developers/android-cache-cleaner)
2 | ======================
3 |
4 | Cache Cleaner for Android:
5 |
6 | - KISS philosophy
7 | - **No ads**
8 | - Fast and clean
9 | - Does not require root
10 |
11 | That says it all.
12 |
13 | Deprecation
14 | -----------
15 | You do not need this app anymore if you are on Android 6.0 or newer. Just go to `Settings` ->
16 | `Storage & USB`-> `Internal storage` and click on `Cached data` in order to clear all the cache.
17 |
18 | Partial incompatibility with Android 6.0 and newer
19 | ------------------------------------------
20 | Starting with Android 6.0, ```CLEAR_APP_CACHE``` permission seems to be no longer available to
21 | regular applications and since this permission is required for cleaning of internal cache, Cache
22 | Cleaner is not able to clean internal cache on Android 6.0 and newer. However, cleaning of external
23 | cache is still supported.
24 |
25 | Download
26 | --------
27 |
28 | [
](https://play.google.com/store/apps/details?id=com.frozendevs.cache.cleaner)
29 | [](https://f-droid.org/repository/browse/?fdid=com.frozendevs.cache.cleaner)
30 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':CacheCleaner'
2 |
--------------------------------------------------------------------------------