├── .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 | 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 | 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 | 3 | 4 | 9 | 10 | 15 | 16 | 22 | 23 | 27 | 28 | 32 | 33 | 37 | 38 | 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 [![Build Status](https://travis-ci.org/Frozen-Developers/android-cache-cleaner.svg)](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 | [Google Play Store](https://play.google.com/store/apps/details?id=com.frozendevs.cache.cleaner) 29 | [![F-Droid](https://guardianproject.info/wp-content/uploads/2014/07/logo-fdroid.png)](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 | --------------------------------------------------------------------------------