Commit 259dc618 authored by wanglei's avatar wanglei

...初始化

parent a46a6377
Pipeline #1364 canceled with stages
*.iml
.gradle
/local.properties
.idea
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
/build
\ No newline at end of file
plugins {
id("com.android.application")
id("com.google.gms.google-services")
}
android {
namespace = "com.swiftcleaner.chovey"
compileSdk = 33
defaultConfig {
applicationId = "com.clean_swift"
minSdk = 28
targetSdk = 33
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
// 添加签名配置
signingConfigs {
create("release") {
storeFile = file("../my-key.keystore")
storePassword = "123456"
keyAlias = "my_alias"
keyPassword = "123456"
}
}
buildTypes {
release {
isMinifyEnabled = false
signingConfig = signingConfigs.getByName("release")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding = true
}
dependenciesInfo {
includeInApk = true
}
}
dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.8.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
//底部弹窗
api("com.google.android.material:material:1.4.0")
api("com.github.bumptech.glide:glide:4.15.1")
api("com.geyifeng.immersionbar:immersionbar:3.2.2")
api("com.airbnb.android:lottie:5.2.0")
implementation ("com.google.firebase:firebase-messaging:23.2.1")
}
\ No newline at end of file
{
"project_info": {
"project_number": "727258703276",
"project_id": "aptest-3b5b8",
"storage_bucket": "aptest-3b5b8.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:727258703276:android:12779d155095b8426f8609",
"android_client_info": {
"package_name": "com.clean_swift"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyCxM6UApG-Wzav01u5EyWQyFZYDFFW4m0k"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
package com.swiftcleaner.chovey;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.swiftcleaner.chovey", appContext.getPackageName());
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.READ_NOTIFICATIONS" />
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
</intent>
</queries>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/logo"
android:label="@string/app_name"
android:roundIcon="@mipmap/logo"
android:supportsRtl="true"
android:theme="@style/Theme.SwiftCleanerPhoneHelper"
tools:targetApi="31">
<!-- 注册广播 -->
<service
android:name=".model.service.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<!-- <receiver-->
<!-- android:name="自定义 Receiver"-->
<!-- android:enabled="true"-->
<!-- android:exported="false" >-->
<!-- <intent-filter>-->
<!-- <action android:name="cn.jpush.android.intent.RECEIVER_MESSAGE" />-->
<!-- <category android:name="com.clean_swift" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<activity
android:name=".view.activity.SimilarPhotosActivity"
android:exported="false" />
<activity
android:name=".view.activity.WhatsAppActivity"
android:exported="false" />
<activity
android:name=".view.activity.ScreenShotActivity"
android:exported="false" />
<activity
android:name=".view.activity.LargeFileActivity"
android:exported="false" />
<activity
android:name=".view.activity.AppProcessActivity"
android:exported="false" />
<activity
android:name=".view.activity.InfoActivity"
android:exported="false" />
<activity
android:name=".view.activity.BatteryInfoActivity"
android:exported="false" />
<activity
android:name=".view.activity.EndCleanJunkActivity"
android:exported="false" />
<activity
android:name=".view.activity.SettingActivity"
android:exported="false" />
<activity
android:name=".view.activity.CleanJunkActivity"
android:exported="false" />
<activity
android:name=".view.activity.StartActivity"
android:exported="true"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".view.MainActivity"
android:exported="false" /> <!-- 今日头条autosize 屏幕适配 -->
<meta-data
android:name="design_width_in_dp"
android:value="360" />
<meta-data
android:name="design_height_in_dp"
android:value="640" /> <!-- 适配华为(huawei)刘海屏 沉浸式 -->
<meta-data
android:name="android.notch_support"
android:value="true" /> <!-- 适配小米(xiaomi)刘海屏 -->
<meta-data
android:name="notch.config"
android:value="portrait|landscape" />
<meta-data
android:name="android.max_aspect"
android:value="2.4" />
</application>
</manifest>
\ No newline at end of file
package com.swiftcleaner.chovey.model.bean;
import android.graphics.drawable.Drawable;
public class AppInfo {
private Drawable icon;
private String appName;
private long memoryUsage;
public AppInfo(Drawable icon, String appName, long memoryUsage) {
this.icon = icon;
this.appName = appName;
this.memoryUsage = memoryUsage;
}
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public long getMemoryUsage() {
return memoryUsage;
}
public void setMemoryUsage(long memoryUsage) {
this.memoryUsage = memoryUsage;
}
}
package com.swiftcleaner.chovey.model.bean;
import android.graphics.drawable.Drawable;
public class AppInfoBean {
private String appName;
private Drawable appIcon;
private String packageName;
public AppInfoBean(String appName, Drawable appIcon, String packageName) {
this.appName = appName;
this.appIcon = appIcon;
this.packageName = packageName;
}
// Getters and setters
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public Drawable getAppIcon() {
return appIcon;
}
public void setAppIcon(Drawable appIcon) {
this.appIcon = appIcon;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
}
package com.swiftcleaner.chovey.model.bean;
import android.graphics.Bitmap;
import java.util.List;
public class CleanFileBean {
private String name;
private String path;
private int icon;
private Bitmap icon1;
private long length;
private long lastModified;
private String mineType;
private boolean isSelected;
private boolean isScanning;
private int state;
private int type;
private List<CleanFileBean> items;
public CleanFileBean(String name) {
this(name, "", 0, 0, 0, "", false, true, 0, 0, null);
}
public CleanFileBean() {
}
public CleanFileBean(String name, String path, String mineType) {
this.name = name;
this.path = path;
this.mineType = mineType;
}
public CleanFileBean(String name, String path, long length) {
this.name = name;
this.path = path;
this.length = length;
}
public CleanFileBean(String name, String path, Bitmap icon1, long length) {
this.name = name;
this.path = path;
this.icon1 = icon1;
this.length = length;
}
public CleanFileBean(String name, Bitmap icon1, long length) {
this.name = name;
this.icon1 = icon1;
this.length = length;
}
public CleanFileBean(String name, String path, int icon1, long length, long lastModified, String mineType, boolean isSelected, boolean isScanning, int state, int type, List<CleanFileBean> items) {
this.name = name;
this.path = path;
this.icon = icon1;
this.length = length;
this.lastModified = lastModified;
this.mineType = mineType;
this.isSelected = isSelected;
this.isScanning = isScanning;
this.state = state;
this.type = type;
this.items = items;
}
public CleanFileBean(String name, String path, int icon, long length, long lastModified, String mineType) {
this.name = name;
this.path = path;
this.icon = icon;
this.length = length;
this.lastModified = lastModified;
this.mineType = mineType;
}
public CleanFileBean(Bitmap icon1, Long length,String path) {
this.icon1=icon1;
this.length = length;
this.path = path;
}
// public CleanFileBean(String displayName, String filePath, Bitmap icon1, long size, long dateModified, String mimeType) {
// this.name = displayName;
// this.path = filePath;
// this.icon1 = icon1;
// this.lastModified = dateModified;
// this.mineType = mimeType;
// }
public CleanFileBean(String name, String path, Bitmap icon1, long length, long lastModified, String mineType) {
this.name = name;
this.path = path;
this.icon1 = icon1;
this.length = length;
this.lastModified = lastModified;
this.mineType = mineType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
public long getLastModified() {
return lastModified;
}
public void setLastModified(long lastModified) {
this.lastModified = lastModified;
}
public String getMineType() {
return mineType;
}
public void setMineType(String mineType) {
this.mineType = mineType;
}
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
public boolean isScanning() {
return isScanning;
}
public void setScanning(boolean scanning) {
isScanning = scanning;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public List<CleanFileBean> getItems() {
return items;
}
public void setItems(List<CleanFileBean> items) {
this.items = items;
}
@Override
public String toString() {
return "FileBean{" +
"name='" + name + '\'' +
", path='" + path + '\'' +
", icon=" + icon +
", length=" + length +
", lastModified=" + lastModified +
", mineType='" + mineType + '\'' +
", isSelected=" + isSelected +
", isScanning=" + isScanning +
", state=" + state +
", type=" + type +
", items=" + items +
'}';
}
public Bitmap getIcon1() {
return icon1;
}
public void setIcon1(Bitmap icon1) {
this.icon1 = icon1;
}
}
package com.swiftcleaner.chovey.model.bean;
public class DialogLargeFileBean {
String name;
Boolean isChecked;
public DialogLargeFileBean(String name, Boolean isChecked) {
this.name = name;
this.isChecked = isChecked;
}
public DialogLargeFileBean() {
}
public DialogLargeFileBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getChecked() {
return isChecked;
}
public void setChecked(Boolean checked) {
isChecked = checked;
}
}
package com.swiftcleaner.chovey.model.bean;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.ThumbnailUtils;
import java.io.File;
/**
* 作者:马海钊
* 时间:2024/12/18 16:47
* 功能:
*/
public class ImageHelpers {
// 加载 Bitmap 从文件路径
private static Bitmap loadBitmapFromFile(String path) {
Bitmap bitmap = BitmapFactory.decodeFile(path);
if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
return null;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
if (options.outHeight == -1 || options.outWidth == -1) {
return null;
}
int inSampleSize = (int) (0.5f + options.outHeight / (float) bitmap.getHeight()) >= (int) (0.5f + options.outWidth / (float) bitmap.getWidth())
? (int) (0.5f + options.outHeight / (float) bitmap.getHeight()) : (int) (0.5f + options.outWidth / (float) bitmap.getWidth());
inSampleSize++;
options.inSampleSize = inSampleSize >= 1 ? inSampleSize : 1;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
// 创建图片的相似性对象
public static SimilarBean createImage(String path) {
try {
int width = 8;
int height = 8;
Bitmap source = loadBitmapFromFile(path);
Bitmap thumb = ThumbnailUtils.extractThumbnail(source, width, height);
int[] pixels = new int[width * height];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
pixels[i * height + j] = rgbToGray(thumb.getPixel(i, j));
}
}
int avgPixel = average(pixels);
int[] comps = new int[width * height];
for (int i = 0; i < comps.length; i++) {
if (pixels[i] >= avgPixel) {
comps[i] = 1;
} else {
comps[i] = 0;
}
}
StringBuilder hashCode = new StringBuilder();
for (int i = 0; i < comps.length; i += 4) {
int result = comps[i] * (int) Math.pow(2, 3) + comps[i + 1] * (int) Math.pow(2, 2) + comps[i + 2] * (int) Math.pow(2, 1) + comps[i + 3];
hashCode.append(binaryToHex(result));
}
recycleBitmap(thumb);
recycleBitmap(source);
return new SimilarBean(path, hashCode.toString(), avgPixel, new File(path).length(), false);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 将 RGB 值转换为灰度值
private static int rgbToGray(int pixels) {
int red = Color.red(pixels);
int green = Color.green(pixels);
int blue = Color.blue(pixels);
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);
}
// 计算像素数组的平均值
private static int average(int[] pixels) {
int sum = 0;
for (int pixel : pixels) {
sum += pixel;
}
return sum / pixels.length;
}
// 回收 Bitmap
private static void recycleBitmap(Bitmap thumb) {
if (thumb != null && !thumb.isRecycled()) {
thumb.recycle();
}
}
// 判断两张图片的相似性条件
public static boolean similarCondition(SimilarBean first, SimilarBean second) {
return hammingDistance(first.getHashCode(), second.getHashCode()) <= 6 && (first.getAvgPixel() / (float) second.getAvgPixel()) >= 0.8 && (first.getAvgPixel() / (float) second.getAvgPixel()) <= 1.0;
}
// 计算汉明距离
private static int hammingDistance(String sourceHashCode, String hashCode) {
int difference = 0;
for (int i = 0; i < sourceHashCode.length(); i++) {
if (sourceHashCode.charAt(i) != hashCode.charAt(i)) {
difference++;
}
}
return difference;
}
// 将二进制转换为十六进制
private static char binaryToHex(int binary) {
switch (binary) {
case 0:
return '0';
case 1:
return '1';
case 2:
return '2';
case 3:
return '3';
case 4:
return '4';
case 5:
return '5';
case 6:
return '6';
case 7:
return '7';
case 8:
return '8';
case 9:
return '9';
case 10:
return 'a';
case 11:
return 'b';
case 12:
return 'c';
case 13:
return 'd';
case 14:
return 'e';
case 15:
return 'f';
default:
return ' ';
}
}
}
package com.swiftcleaner.chovey.model.bean;
import android.graphics.Bitmap;
public class MeCleanBean {
private int id;
private int icon;
private Bitmap icon1;
private String name;
private String path;
private String size;
private boolean isChecked;
public MeCleanBean(int icon, String name, String size) {
this.icon = icon;
this.name = name;
this.size = size;
}
public MeCleanBean(Bitmap icon1, String name, String size) {
this.icon1 = icon1;
this.name = name;
this.size = size;
}
public MeCleanBean(int icon, String name, String path, String size, boolean isChecked) {
this.icon = icon;
this.name = name;
this.path = path;
this.size = size;
this.isChecked = isChecked;
}
public MeCleanBean(int id, boolean isChecked) {
this.id = id;
this.isChecked = isChecked;
}
public MeCleanBean(String name, String path, String size) {
this.name = name;
this.path = path;
this.size = size;
}
public Bitmap getIcon1() {
return icon1;
}
public void setIcon1(Bitmap icon1) {
this.icon1 = icon1;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public MeCleanBean(int icon, String name, String path, String size) {
this.icon = icon;
this.name = name;
this.path = path;
this.size = size;
}
public MeCleanBean(int icon, String name) {
this.icon = icon;
this.name = name;
}
public MeCleanBean(String size, boolean isChecked) {
this.size = size;
this.isChecked = isChecked;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
@Override
public String toString() {
return "MeCleanBean{" +
"id=" + id +
", isChecked=" + isChecked +
'}';
}
}
package com.swiftcleaner.chovey.model.bean;
import android.graphics.Bitmap;
public class ScreenShotBean {
private int icon;
private String size;
private Boolean isChecked = false;
private Bitmap icon1;
private String path;
public ScreenShotBean(int icon, String size, Boolean isChecked) {
this.icon = icon;
this.size = size;
this.isChecked = isChecked;
}
public ScreenShotBean(int icon, String size) {
this.icon = icon;
this.size = size;
}
public ScreenShotBean(String size, Bitmap icon1,String path) {
this.size = size;
this.icon1 = icon1;
this.path=path;
}
public Bitmap getIcon1() {
return icon1;
}
public void setIcon1(Bitmap icon1) {
this.icon1 = icon1;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public Boolean getChecked() {
return isChecked;
}
public void setChecked(Boolean checked) {
isChecked = checked;
}
}
package com.swiftcleaner.chovey.model.bean;
import java.util.ArrayList;
import java.util.List;
public class SimilarBean {
private String url;
private String hashCode;
private int avgPixel;
private long size;
private boolean isSelect;
private List<SimilarBean> items;
// Constructor
public SimilarBean(String url, String hashCode, int avgPixel, long size, boolean isSelect) {
this.url = url;
this.hashCode = hashCode;
this.avgPixel = avgPixel;
this.size = size;
this.isSelect = isSelect;
this.items = new ArrayList<>();
}
// Getters and Setters
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getHashCode() {
return hashCode;
}
public void setHashCode(String hashCode) {
this.hashCode = hashCode;
}
public int getAvgPixel() {
return avgPixel;
}
public void setAvgPixel(int avgPixel) {
this.avgPixel = avgPixel;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public boolean isSelect() {
return isSelect;
}
public void setSelect(boolean select) {
isSelect = select;
}
public List<SimilarBean> getItems() {
return items;
}
public void setItems(List<SimilarBean> items) {
this.items = items;
}
// Method to add a SimilarBean to the list
public void addItem(SimilarBean item) {
this.items.add(item);
}
// Override toString for easy debugging
@Override
public String toString() {
return "SimilarBean{" +
"url='" + url + '\'' +
", hashCode='" + hashCode + '\'' +
", avgPixel=" + avgPixel +
", size=" + size +
", isSelect=" + isSelect +
", items=" + items +
'}';
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.model.bean;
public class bean {
String name;
int num;
public bean(String name, int num) {
this.name = name;
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
package com.swiftcleaner.chovey.model.service;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// 处理收到的消息
if (remoteMessage.getNotification() != null) {
String title = remoteMessage.getNotification().getTitle();
String body = remoteMessage.getNotification().getBody();
sendNotification(title, body);
}
}
private void sendNotification(String title, String body) {
// 这里实现通知的发送逻辑
}
@Override
public void onNewToken(String token) {
// 每当生成新的令牌时调用
sendRegistrationToServer(token);
}
private void sendRegistrationToServer(String token) {
// 将令牌发送到你的服务器
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.model.tool;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import java.util.List;
public class AppUtils {
public static int getNonSystemAppCount(Context context) {
PackageManager packageManager = context.getPackageManager();
List<ApplicationInfo> installedApps = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
int nonSystemAppCount = 0;
for (ApplicationInfo appInfo : installedApps) {
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
// 非系统应用
nonSystemAppCount++;
}
}
return nonSystemAppCount;
}
}
package com.swiftcleaner.chovey.model.tool;
/**
* 作者:马海钊
* 时间:2024/12/11 21:45
* 功能:
*/
import android.os.Handler;
import android.os.Looper;
import java.io.File;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FileDeleter {
private ExecutorService executorService;
public FileDeleter() {
this.executorService = Executors.newCachedThreadPool();
}
public FileDeleter deleteFiles(List<String> filePaths, OnFilesDeletedListener listener) {
executorService.execute(() -> {
for (String filePath : filePaths) {
File file = new File(filePath);
if (file.exists() && file.delete()) {
// 文件删除成功,立即回调
new Handler(Looper.getMainLooper()).post(() -> {
if (listener != null) {
listener.onFileDeleted(true, filePath);
}
});
} else {
// 文件删除失败,立即回调
new Handler(Looper.getMainLooper()).post(() -> {
if (listener != null) {
listener.onFileDeleted(false, filePath);
}
});
}
}
});
return this; // 返回当前实例
}
public void shutdown() {
executorService.shutdown(); // 关闭线程池
}
public interface OnFilesDeletedListener {
void onFileDeleted(boolean success, String filePath);
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.model.tool;
import android.os.Environment;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import com.swiftcleaner.chovey.model.bean.MeCleanBean;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FileHelps {
private static final String WHATS_APP_MEDIA_DIR = "Android/media/com.whatsapp/WhatsApp/Media/";
public static List<CleanFileBean> findWhatsappFiles() {
File rootDir = new File(getAppSpecificDirPath(WHATS_APP_MEDIA_DIR));
return findFilesRecursive(rootDir, new String[]{});
}
//查找外部存储中的空文件夹
public static List<CleanFileBean> findEmptyFolders() {
File externalStorageDir = Environment.getExternalStorageDirectory();
String[] filters = new String[]{"/storage/emulated/0/Android/data", "/storage/emulated/0/Android/obb"};
List<File> emptyFolders = getAllEmptyFolders(externalStorageDir, filters);
return emptyFolders.stream()
.map(folder -> new CleanFileBean(folder.getName(), folder.getPath(), 4 * 1024))
.collect(Collectors.toList());
}
//查找外部存储目录下以.temp 为后缀的文件。
public static List<CleanFileBean> findTempFiles() {
File rootDir = Environment.getExternalStorageDirectory();
return findFilesRecursive(rootDir, new String[]{".temp"});
}
//查找外部存储目录下以.apk 和.aab 为后缀的文件。
public static List<CleanFileBean> findApkFiles() {
File rootDir = Environment.getExternalStorageDirectory();
return findFilesRecursive(rootDir, new String[]{".apk", ".aab"});
}
//查找外部存储目录下以.log 为后缀的文件。
public static List<CleanFileBean> findLogFiles() {
File rootDir = Environment.getExternalStorageDirectory();
return findFilesRecursive(rootDir, new String[]{".log"});
}
public static void deleteFile(String filePath) {
File file = new File(filePath);
deleteIfExists(file);
}
private static boolean deleteIfExists(File file) {
if (file != null && file.exists()) {
return file.delete();
}
return false;
}
private static List<CleanFileBean> findFilesRecursive(File dir, String[] suffixes) {
try {
return Files.walk(dir.toPath())
.filter(Files::isRegularFile)
.filter(path -> Arrays.stream(suffixes).anyMatch(suffix -> path.getFileName().toString().endsWith(suffix)))
.map(path -> {
File file = path.toFile();
return new CleanFileBean(file.getName(), file.getPath(), file.length());
})
.collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
return Collections.emptyList();
}
}
private boolean endsWith(File file, String[] suffixes) {
if (suffixes.length == 0) {
return true;
}
String fileName = file.getName().toLowerCase();
for (String suffix : suffixes) {
if (fileName.endsWith(suffix.toLowerCase())) {
return true;
}
}
return false;
}
private static String getAppSpecificDirPath(String relativePath) {
return Environment.getExternalStorageDirectory() + "/" + relativePath;
}
private static List<File> getAllEmptyFolders(File root, String[] filters) {
File[] files = root.listFiles();
if (files == null) {
return Collections.emptyList();
}
return Stream.of(files)
.flatMap(file -> getAllEmptyFolders(file, filters).stream())
.filter(folder -> folder.isDirectory() &&!contains(filters, folder.getPath()) &&!folder.isHidden() && folder.list()!= null && folder.list().length == 0)
.collect(Collectors.toList());
}
private static boolean contains(String[] filters, String path) {
for (String filter : filters) {
if (filter.equals(path)) {
return true;
}
}
return false;
}
}
package com.swiftcleaner.chovey.model.tool;
public class FileSizeUtil {
// 定义单位
private static final long KB = 1024;
private static final long MB = KB * 1024;
private static final long GB = MB * 1024;
public static String getAutoFileSize(long length) {
if (length < KB) {
return length + " B";
} else if (length < MB) {
return String.format("%.2f KB", (double) length / KB);
} else if (length < GB) {
return String.format("%.2f MB", (double) length / MB);
} else {
return String.format("%.2f GB", (double) length / GB);
}
}
}
package com.swiftcleaner.chovey.model.tool;
import com.swiftcleaner.chovey.model.util.FileUtils;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* 作者:马海钊
* 时间:2024/12/17 19:12
* 功能:
*/
public class FileTypes {
// 图像后缀列表(可变)
public static final List<String> images = new ArrayList<>(Arrays.asList(".jpeg", ".jpg", ".png", ".gif", ".webp", ".ico", ".raw"));
// 视频后缀列表(可变)
public static final List<String> videos = new ArrayList<>(Arrays.asList(".mp4", ".avi", ".mov", ".wmv", ".flv"));
// 音频后缀列表(可变)
public static final List<String> audios = new ArrayList<>(Arrays.asList(".mp3", ".wav", ".m4a", ".ncm"));
}
package com.swiftcleaner.chovey.model.tool;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.File;
import android.graphics.Color;
import android.media.ThumbnailUtils;
import com.swiftcleaner.chovey.model.bean.SimilarBean;
class SimilarBeanJava {
private String url;
private String hashCode;
private int avgPixel;
private long size;
private boolean isSelect;
public SimilarBeanJava(String url, String hashCode, int avgPixel, long size, boolean isSelect) {
this.url = url;
this.hashCode = hashCode;
this.avgPixel = avgPixel;
this.size = size;
this.isSelect = isSelect;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getHashCode() {
return hashCode;
}
public void setHashCode(String hashCode) {
this.hashCode = hashCode;
}
public int getAvgPixel() {
return avgPixel;
}
public void setAvgPixel(int avgPixel) {
this.avgPixel = avgPixel;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public boolean isSelect() {
return isSelect;
}
public void setSelect(boolean select) {
isSelect = select;
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.model.tool;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.text.TextUtils;
import androidx.annotation.RequiresApi;
import androidx.collection.ArrayMap;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import android.util.Pair;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class MediaHelps {
private static final String[] PROJECTION = {
MediaStore.Files.FileColumns.DISPLAY_NAME,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.SIZE,
MediaStore.Files.FileColumns.DATE_MODIFIED,
MediaStore.Files.FileColumns.MIME_TYPE,
MediaStore.Files.FileColumns._ID
};
private static final String EXTERNAL = "external";
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static void updateMedia(Context context, String[] paths) {
MediaScannerConnection.scanFile(context, paths, null, null);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static List<CleanFileBean> findFiles(Context context, long size) {
return queryFilesWithSize(context, MediaStore.Files.getContentUri(EXTERNAL), size);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static List<CleanFileBean> findSpecifiedFiles(Context context) {
String[] suffixes = { "%.log", "%.apk", "%.aab", "%.temp", "%.LOG", "%.APK", "%.AAB", "%.TEMP" };
return queryFilesWithSuffixes(context, MediaStore.Files.getContentUri(EXTERNAL), suffixes);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static Map<String, List<CleanFileBean>> findScreenshotsFiles(Context context) {
String selection = MediaStore.Images.Media.RELATIVE_PATH + " LIKE ?";
String[] selectionArgs = { "%Screenshots%" };
List<CleanFileBean> list = query(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION, selection, selectionArgs);
Map<String, List<CleanFileBean>> map = new ArrayMap<>();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM", Locale.getDefault());
for (CleanFileBean file : list) {
String dateKey = dateFormat.format(new Date(file.getLastModified()));
map.putIfAbsent(dateKey, new ArrayList<>());
map.get(dateKey).add(file);
}
return map;
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static List<CleanFileBean> findImageFiles(Context context, long size) {
return queryFilesWithSize(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, size);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static List<CleanFileBean> findVideoFiles(Context context, long size) {
return queryFilesWithSize(context, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, size);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static List<CleanFileBean> findAudioFiles(Context context, long size) {
return queryFilesWithSize(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, size);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static List<CleanFileBean> findDocFiles(Context context, long size) {
String[] mimeTypes = {
"text/plain",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/pdf",
};
return queryFilesWithMimeTypes(context, MediaStore.Files.getContentUri(EXTERNAL), mimeTypes, size);
}
//文件类型(如图片、视频等)来查找文件
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private static List<CleanFileBean> queryFilesWithSuffixes(Context context, Uri uri, String[] suffixes) {
String[] selectionArgs = new String[suffixes.length];
for (int i = 0; i < suffixes.length; i++) {
selectionArgs[i] = suffixes[i];
}
String selection = TextUtils.join(" OR ", Collections.nCopies(suffixes.length, "LOWER(" + MediaStore.Files.FileColumns.DISPLAY_NAME + ") LIKE ?"));
return query(context, uri, PROJECTION, selection, selectionArgs);
}
//该方法用于查找大小大于或等于指定值的文件,适用于清理大文件或者查找特定大小范围的文件。
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private static List<CleanFileBean> queryFilesWithSize(Context context, Uri uri, long size) {
String selection = null;
String[] selectionArgs = null;
if (size > 0) {
selection = MediaStore.Files.FileColumns.SIZE + " >= ?";
selectionArgs = new String[]{String.valueOf(size)};
}
return query(context, uri, PROJECTION, selection, selectionArgs);
}
//该方法通过文件的 MIME 类型和大小来筛选文件,适用于需要根据文件类型和大小来进行更精细查询的场景。
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private static List<CleanFileBean> queryFilesWithMimeTypes(Context context, Uri uri, String[] mimeTypes, long size) {
Pair<String, String[]> selection = buildSelectionWithMimeTypes(mimeTypes, size);
return query(context, uri, PROJECTION, selection.first, selection.second);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private static Pair<String, String[]> buildSelectionWithMimeTypes(String[] mimeTypes, long size) {
String mimeTypeConditions = TextUtils.join(" OR ", Arrays.asList(mimeTypes)).replace("?", "${MediaStore.Files.FileColumns.MIME_TYPE}=?");
String sizeCondition = MediaStore.Files.FileColumns.SIZE + " >= ?";
String selection = "(" + mimeTypeConditions + ") AND (" + sizeCondition + ")";
String[] selectionArgs = Arrays.copyOf(mimeTypes, mimeTypes.length + 1);
selectionArgs[mimeTypes.length] = String.valueOf(size);
return new Pair<>(selection, selectionArgs);
}
public static List<CleanFileBean> query(
Context context,
Uri uri,
String[] projection,
String selection,
String[] selectionArgs) {
List<CleanFileBean> list = new ArrayList<>();
Cursor cursor = null;
try {
String sortOrder = MediaStore.Files.FileColumns.DATE_MODIFIED + " DESC";
cursor = context.getContentResolver().query(
uri,
projection,
selection,
selectionArgs,
sortOrder
);
if (cursor != null) {
while (cursor.moveToNext()) {
@SuppressLint("Range") String displayName = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));
@SuppressLint("Range") String filePath = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));
@SuppressLint("Range") long size = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns.SIZE));
@SuppressLint("Range") long dateModified = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED)) * 1000;
@SuppressLint("Range") String mimeType = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE));
// 加载缩略图
@SuppressLint("Range") Bitmap icon = MediaStore.Images.Thumbnails.getThumbnail(
context.getContentResolver(),
cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns._ID)),
MediaStore.Images.Thumbnails.MINI_KIND,
null
);
CleanFileBean fileBean = new CleanFileBean(displayName, filePath, icon, size, dateModified, mimeType);
fileBean.setIcon1(icon); // 设置缩略图
fileBean.setLength(size);
list.add(fileBean);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
return list;
}
}
package com.swiftcleaner.chovey.model.tool;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Debug;
import android.os.StatFs;
import java.io.File;
public class MemoryUtils {
// 获取手机磁盘总内存
public static String getTotalDiskMemory(Context context) {
File path = context.getFilesDir().getAbsoluteFile();
StatFs statFs = new StatFs(path.getPath());
long blockSize = statFs.getBlockSizeLong();
long totalBlocks = statFs.getBlockCountLong();
long totalMemory = totalBlocks * blockSize;
return String.format("%.1f", totalMemory / 1024f / 1024f / 1024f) + " GB"; // Convert to GB and format to one decimal place
}
// 获取手机磁盘已用内存
public static String getUsedDiskMemory(Context context) {
File path = context.getFilesDir().getAbsoluteFile();
StatFs statFs = new StatFs(path.getPath());
long blockSize = statFs.getBlockSizeLong();
long totalBlocks = statFs.getBlockCountLong();
long availableBlocks = statFs.getAvailableBlocksLong();
long totalMemory = totalBlocks * blockSize;
long availableMemory = availableBlocks * blockSize;
long usedMemory = totalMemory - availableMemory; // Calculate used memory
return String.format("%.1f", usedMemory / 1024f / 1024f / 1024f) + " GB"; // Convert to GB and format to one decimal place
}
public static String getUsedDiskMemoryPercent(Context context) {
File path = context.getFilesDir().getAbsoluteFile();
StatFs statFs = new StatFs(path.getPath());
long blockSize = statFs.getBlockSizeLong();
long totalBlocks = statFs.getBlockCountLong();
long availableBlocks = statFs.getAvailableBlocksLong();
long totalMemory = totalBlocks * blockSize;
long availableMemory = availableBlocks * blockSize;
long usedMemory = totalMemory - availableMemory; // Calculate used memory
// Calculate the percentage
double usedMemoryPercent = ((double) usedMemory / (double) totalMemory) * 100;
// Format the percentage to an integer
return String.format("%d", (int) usedMemoryPercent);
}
}
package com.swiftcleaner.chovey.model.tool;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import com.swiftcleaner.chovey.R;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class RadarView extends View {
private Context mContext;
private boolean isSearching = false;// 标识是否处于扫描状态,默认为不在扫描状态
private Paint mPaint;// 画笔
private Bitmap mScanBmp;// 执行扫描运动的图片
private int mOffsetArgs = 0;// 扫描运动偏移量参数
private Bitmap mDefaultPointBmp;// 标识设备的圆点-默认
private Bitmap mLightPointBmp;// 标识设备的圆点-高亮
private int mPointCount = 0;// 圆点总数
private List<String> mPointArray = new ArrayList<String>();// 存放偏移量的map
private Random mRandom = new Random();
private int mWidth, mHeight;// 宽高
int mOutWidth;// 外圆宽度(w/4/5*2=w/10)
int mCx, mCy;// x、y轴中心点
int mOutsideRadius, mInsideRadius;// 外、内圆半径
public RadarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// Auto-generated constructor stub
init(context);
}
public RadarView(Context context, AttributeSet attrs) {
super(context, attrs);
// Auto-generated constructor stub
init(context);
}
public RadarView(Context context) {
super(context);
// Auto-generated constructor stub
init(context);
}
/**
* <提前初始化好需要使用的对象,避免在绘制过程中多次初始化>
*
* @return void
*/
private void init(Context context) {
mPaint = new Paint();
this.mContext = context;
this.mDefaultPointBmp = Bitmap.createBitmap(BitmapFactory
.decodeResource(mContext.getResources(),
R.mipmap.dongxiao));
this.mLightPointBmp = Bitmap.createBitmap(BitmapFactory.decodeResource(
mContext.getResources(), R.mipmap.dongxiao));
}
/**
* 测量视图及其内容,以确定所测量的宽度和高度(测量获取控件尺寸).
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获取控件区域宽高
if (mWidth == 0 || mHeight == 0) {
final int minimumWidth = getSuggestedMinimumWidth();
final int minimumHeight = getSuggestedMinimumHeight();
mWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
mHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
mScanBmp = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(
mContext.getResources(), R.mipmap.dongxiao), mWidth
- mOutWidth, mWidth - mOutWidth, false);
// 获取x/y轴中心点
mCx = mWidth / 2;
mCy = mHeight / 2;
// 获取外圆宽度
mOutWidth = mWidth / 10;
// 计算内、外半径
mOutsideRadius = mWidth / 2;// 外圆的半径
mInsideRadius = (mWidth - mOutWidth) / 4 / 2;// 内圆的半径,除最外层,其它圆的半径=层数*insideRadius
}
}
/**
* 绘制视图--从外部向内部绘制
*/
@Override
protected void onDraw(Canvas canvas) {
// Auto-generated method stub
super.onDraw(canvas);
// 开始绘制最外层的圆
mPaint.setAntiAlias(true);// 设置抗锯齿
mPaint.setStyle(Paint.Style.FILL);// 设置填充样式
// 开始绘制内4圆
mPaint.setColor(0x1AFFFFFF); // 10%透明度的白色
canvas.drawCircle(mCx, mCy, mInsideRadius * 4, mPaint);
// 开始绘制内3圆
mPaint.setColor(0x1AFFFFFF); // 10%透明度的白色
canvas.drawCircle(mCx, mCy, mInsideRadius * 3, mPaint);
// 开始绘制内2圆
mPaint.setColor(0x1AFFFFFF); // 10%透明度的白色
canvas.drawCircle(mCx, mCy, mInsideRadius * 2, mPaint);
// 开始绘制内1圆
mPaint.setColor(0x1AFFFFFF); // 10%透明度的白色
canvas.drawCircle(mCx, mCy, mInsideRadius * 1, mPaint);
// 2.开始绘制对角线
// canvas.drawLine(mOutWidth / 2, mCy, mWidth - mOutWidth / 2, mCy, mPaint);// 绘制0°~180°对角线
// canvas.drawLine(mCx, mHeight - mOutWidth / 2, mCx, mOutWidth / 2,
// mPaint);// 绘制90°~270°对角线
// 根据角度绘制对角线
int startX, startY, endX, endY;
double radian;
// 绘制45°~225°对角线
// 计算开始位置x/y坐标点
radian = Math.toRadians((double) 45);// 将角度转换为弧度
startX = (int) (mCx + mInsideRadius * 4 * Math.cos(radian));// 通过圆心坐标、半径和当前角度计算当前圆周的某点横坐标
startY = (int) (mCy + mInsideRadius * 4 * Math.sin(radian));// 通过圆心坐标、半径和当前角度计算当前圆周的某点纵坐标
// 计算结束位置x/y坐标点
radian = Math.toRadians((double) 45 + 180);
endX = (int) (mCx + mInsideRadius * 4 * Math.cos(radian));
endY = (int) (mCy + mInsideRadius * 4 * Math.sin(radian));
// canvas.drawLine(startX, startY, endX, endY, mPaint);
// 绘制135°~315°对角线
// 计算开始位置x/y坐标点
radian = Math.toRadians((double) 135);
startX = (int) (mCx + mInsideRadius * 4 * Math.cos(radian));
startY = (int) (mCy + mInsideRadius * 4 * Math.sin(radian));
// 计算结束位置x/y坐标点
radian = Math.toRadians((double) 135 + 180);
endX = (int) (mCx + mInsideRadius * 4 * Math.cos(radian));
endY = (int) (mCy + mInsideRadius * 4 * Math.sin(radian));
// canvas.drawLine(startX, startY, endX, endY, mPaint);
// 3.绘制扫描扇形图
canvas.save();// 用来保存Canvas的状态.save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作.
if (isSearching) {// 判断是否处于扫描
canvas.rotate(mOffsetArgs, mCx, mCy);// 绘制旋转角度,参数一:角度;参数二:x中心;参数三:y中心.
canvas.drawBitmap(mScanBmp, mCx - mScanBmp.getWidth() / 2, mCy
- mScanBmp.getHeight() / 2, null);// 绘制Bitmap扫描图片效果
mOffsetArgs += 3;
} else {
canvas.drawBitmap(mScanBmp, mCx - mScanBmp.getWidth() / 2, mCy
- mScanBmp.getHeight() / 2, null);
}
// 4.开始绘制动态点
canvas.restore();// 用来恢复Canvas之前保存的状态.防止save后对Canvas执行的操作对后续的绘制有影响.
if (mPointCount > 0) {// 当圆点总数>0时,进入下一层判断
if (mPointCount > mPointArray.size()) {// 当圆点总数大于存储坐标点数目时,说明有增加,需要重新生成随机坐标点
int mx = mInsideRadius + mRandom.nextInt(mInsideRadius * 6);
int my = mInsideRadius + mRandom.nextInt(mInsideRadius * 6);
mPointArray.add(mx + "/" + my);
}
// 开始绘制坐标点
for (int i = 0; i < mPointArray.size(); i++) {
String[] result = mPointArray.get(i).split("/");
// 开始绘制动态点
if (i < mPointArray.size() - 1)
canvas.drawBitmap(mDefaultPointBmp,
Integer.parseInt(result[0]),
Integer.parseInt(result[1]), null);
else
canvas.drawBitmap(mLightPointBmp,
Integer.parseInt(result[0]),
Integer.parseInt(result[1]), null);
}
}
if (isSearching)
this.invalidate();
}
/**
* <设置扫描状态>
*
* @return void
*/
public void setSearching(boolean status) {
this.isSearching = status;
this.invalidate();
}
/**
* <新增动态点>
*
* @return void
*/
public void addPoint() {
mPointCount++;
this.invalidate();
}
/**
* <解析获取控件宽高>
*
* @return int
*/
private int resolveMeasured(int measureSpec, int desired) {
int result = 0;
int specSize = MeasureSpec.getSize(measureSpec);
switch (MeasureSpec.getMode(measureSpec)) {
case MeasureSpec.UNSPECIFIED:
result = desired;
break;
case MeasureSpec.AT_MOST:
result = Math.min(specSize, desired);
break;
case MeasureSpec.EXACTLY:
default:
result = specSize;
}
return result;
}
}
package com.swiftcleaner.chovey.model.tool;
import android.content.Context;
import android.widget.Toast;
public class ToastUtil {
public static void showShortToast(FileDeleter.OnFilesDeletedListener context, String message) {
Toast.makeText((Context) context, message, Toast.LENGTH_SHORT).show();
}
public static void showLongToast(Context context, String message) {
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
}
package com.swiftcleaner.chovey.model.util;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build;
public class BatteryReceiver extends BroadcastReceiver {
private Runnable block;
private static final String BATTERY_NOTIFICATION_STATUS_KEY = "batteryNotificationStatus";
private static final String BATTERY_NOTIFICATION_INTERVAL_KEY = "batteryNotificationInterval";
private static final String BATTERY_NOTIFICATION_COUNT_KEY = "batteryNotificationCount";
private static final String BATTERY_NOTIFICATION_CURRENT_KEY = "batteryNotificationCurrent";
private static final String BATTERY_NOTIFICATION_LAST_TIME_KEY = "batteryNotificationLastTime";
public int level = 0;
public int scale = 0;
public int voltage = 0;
public int temperature = 0;
public String technology = "";
public int health = 0;
public int status = 0;
public float mAh = 0f;
public boolean isCharging = false;
public int current = 0; // 电流值,单位为微安培(μA)
public int currentAverage = 0;
public int hours;
public int minutes;
public BatteryReceiver(Runnable block) {
this.block = block;
}
public static void register(Context context) {
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.registerReceiver(new BatteryReceiver(null), intentFilter, Context.RECEIVER_EXPORTED);
} else {
context.registerReceiver(new BatteryReceiver(null), intentFilter);
}
}
@Override
public void onReceive(Context context, Intent intent) {
if (!Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) return;
BatteryManager batteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH, 0);
status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;
int chargeCounter = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER);
int propertyCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
if (chargeCounter != Integer.MIN_VALUE && propertyCapacity != Integer.MIN_VALUE) {
mAh = (chargeCounter / (propertyCapacity / 100f)) / 1000f;
}
current = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW);
// 获取平均电流值,单位为微安培(μA)
currentAverage = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE);
float averagePowerConsumption = 1000; // 假设平均功耗为1000mAh/小时
long remainingTimeHours = (long) (mAh / averagePowerConsumption);
hours = (int) remainingTimeHours;
minutes = (int) ((Math.round((remainingTimeHours - hours) * 60)));
if (block != null) {
block.run();
}
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.model.util;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 作者:马海钊
* 时间:2024/12/17 20:56
* 功能:
*/
public class FileUtils {
public static List<Path> findWhatsappFiles() {
// 指定要搜索的目录
Path directory = Paths.get("path/to/whatsapp/files");
// 创建一个列表来存储符合条件的文件路径
List<Path> foundFiles = new ArrayList<>();
try (Stream<Path> walk = Files.walk(directory)) {
// 过滤文件并添加到列表中
foundFiles = walk.filter(Files::isRegularFile)
.filter(path -> isWhatsappFile(path))
.collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}
return foundFiles;
}
private static boolean isWhatsappFile(Path path) {
// 指定 WhatsApp 文件的后缀
List<String> whatsappSuffixes = Arrays.asList(".mp4", ".3gp", ".jpg", ".jpeg", ".png", ".gif", ".mp3", ".aac");
// 检查文件后缀是否在列表中
return whatsappSuffixes.contains(path.getFileName().toString().toLowerCase(Locale.ROOT).substring(path.getFileName().toString().lastIndexOf('.')));
}
}
package com.swiftcleaner.chovey.model.util;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.activity.result.ActivityResultLauncher;
import android.provider.Settings;
public class PermissionUtils {
public static void requestNotificationPermission(
Context context,
ActivityResultLauncher<Intent> launcher,
ActivityResultLauncher<String[]> permissionsLauncher
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
String[] array = new String[]{android.Manifest.permission.POST_NOTIFICATIONS};
permissionsLauncher.launch(array);
} else {
notificationSettings(context, launcher);
}
}
public static void notificationSettings(
Context context,
ActivityResultLauncher<Intent> launcher
) {
Intent intent = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
} else {
intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
intent.putExtra("app_package", context.getPackageName());
}
launcher.launch(intent);
}
}
package com.swiftcleaner.chovey.view;
import android.app.Application;
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// JPushInterface.setDebugMode(true);
//
// // 调整点一:初始化代码前增加setAuth调用
// boolean isPrivacyReady = false; // app根据是否已弹窗获取隐私授权来赋值
// if(!isPrivacyReady){
// JCollectionAuth.setAuth(context, false); // 后续初始化过程将被拦截
// }
// JPushInterface.init();
//
//
// // 调整点二:隐私政策授权获取成功后调用
// JCollectionAuth.setAuth(context, true); //如初始化被拦截过,将重试初始化过程
}
}
package com.swiftcleaner.chovey.view;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.messaging.FirebaseMessaging;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.databinding.ActivityMainBinding;
import com.swiftcleaner.chovey.model.tool.MemoryUtils;
import com.swiftcleaner.chovey.view.activity.AppProcessActivity;
import com.swiftcleaner.chovey.view.activity.BatteryInfoActivity;
import com.swiftcleaner.chovey.view.activity.CleanJunkActivity;
import com.swiftcleaner.chovey.view.activity.InfoActivity;
import com.swiftcleaner.chovey.view.activity.LargeFileActivity;
import com.swiftcleaner.chovey.view.activity.ScreenShotActivity;
import com.swiftcleaner.chovey.view.activity.SettingActivity;
import com.swiftcleaner.chovey.view.activity.SimilarPhotosActivity;
import com.swiftcleaner.chovey.view.activity.WhatsAppActivity;
import com.swiftcleaner.chovey.view.dialog.AppExitDialog;
import com.swiftcleaner.chovey.view.dialog.CustomBottomSheetDialog;
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
private static final int REQUEST_ALL_FILES_ACCESS_PERMISSION = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initShow();
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
@Override
public void onComplete(@NonNull Task<String> task) {
if (!task.isSuccessful()) {
Log.w("TAG", "Fetching FCM registration token failed", task.getException());
return;
}
// Get new FCM registration token
String token = task.getResult();
// Log and toast
Log.d("TAG", token);
Toast.makeText(MainActivity.this, token, Toast.LENGTH_SHORT).show();
}
});
}
private void initShow() {
//判断是否有权限
checkAndRequestPermissions();
binding.lottieAnimattionView.setAnimation(R.raw.cleaner_junk_found_animation);
binding.lottieAnimattionView.playAnimation();
// 获取总内存
String totalMemory = MemoryUtils.getUsedDiskMemory(this);
// 获取当前使用内存
String usedMemory = MemoryUtils.getTotalDiskMemory(this);
//内存赋值
binding.phoneMemory.setText(totalMemory + "/" + usedMemory);
binding.cleanUp.setOnClickListener(v -> {
intTempJump();
});
binding.ivSetting.setOnClickListener(v -> {
Intent intent = new Intent(this, SettingActivity.class);
startActivity(intent);
});
binding.cl3CleanJunk.setOnClickListener(v -> {
Intent intent = new Intent(this, CleanJunkActivity.class);
startActivity(intent);
});
binding.cl3AppManager.setOnClickListener(v -> {
startActivity(new Intent(this, BatteryInfoActivity.class));
});
binding.cl3BatteryInfo.setOnClickListener(v -> {
startActivity(new Intent(this, InfoActivity.class));
});
binding.appProcess.setOnClickListener(v -> {
startActivity(new Intent(this, AppProcessActivity.class));
});
binding.largeFileCleaner.setOnClickListener(v -> {
startActivity(new Intent(this, LargeFileActivity.class));
});
binding.screenshotCleaner.setOnClickListener(v -> {
startActivity(new Intent(this, ScreenShotActivity.class));
});
binding.whatsApp.setOnClickListener(v -> {
startActivity(new Intent(this, WhatsAppActivity.class));
});
binding.similarPhotos.setOnClickListener(v -> {
startActivity(new Intent(this, SimilarPhotosActivity.class));
});
}
private void checkAndRequestPermissions() {
if (checkFilesAccessPermission(this)) {
// 有权限,直接跳转页面
} else {
// 没有权限,请求权限
CustomBottomSheetDialog customBottomSheetDialog = new CustomBottomSheetDialog();
customBottomSheetDialog.setOnOpenSettingClickListener(isSwitchChecked -> {
if (isSwitchChecked) {
requestFilesAccessPermission();
customBottomSheetDialog.dismiss();
} else {
customBottomSheetDialog.dismiss();
}
});
customBottomSheetDialog.show(getSupportFragmentManager(), "CustomBottomSheetDialog");
}
}
private boolean checkFilesAccessPermission(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
} else {
int readPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE);
int writePermission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
return readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED;
}
}
private void requestFilesAccessPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_ALL_FILES_ACCESS_PERMISSION);
} else {
// 在Android 10及以下版本,请求READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限
// 通常使用请求权限的对话框
// 例如: ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CODE);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_ALL_FILES_ACCESS_PERMISSION) {
if (checkFilesAccessPermission(this)) {
// 权限已授予,跳转页面
} else {
// 权限未授予,显示提示信息或进行其他处理
Toast.makeText(this, "权限未授权", Toast.LENGTH_SHORT).show();
}
}
}
private void intTempJump() {
Intent intent = new Intent(this, CleanJunkActivity.class);
startActivity(intent);
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(true) // 状态栏字体颜色为深色
.navigationBarDarkIcon(false) // 导航栏图标颜色为浅色
.init();
}
@Override
public void onBackPressed() {
AppExitDialog appExitDialog = new AppExitDialog(this);
appExitDialog.setOnDialogClickListener(new AppExitDialog.OnDialogClickListener() {
@Override
public void onCancel() {
appExitDialog.dismiss();
}
@Override
public void onSubmit() {
finish();
}
});
appExitDialog.show();
}
@Override
protected void onResume() {
super.onResume();
if (binding.lottieAnimattionView != null) {
binding.lottieAnimattionView.resumeAnimation(); // 恢复动画
}
}
@Override
protected void onPause() {
super.onPause();
if (binding.lottieAnimattionView != null) {
binding.lottieAnimattionView.pauseAnimation();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (binding.lottieAnimattionView != null) {
binding.lottieAnimattionView.cancelAnimation(); // 停止动画
binding.lottieAnimattionView.clearAnimation(); // 清除动画
binding.lottieAnimattionView.setImageDrawable(null); // 清除图像
binding.lottieAnimattionView.destroyDrawingCache(); // 销毁缓存
}
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Debug;
import android.util.Log;
import android.view.View;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.databinding.ActivityAppProcessBinding;
import com.swiftcleaner.chovey.databinding.ActivityEndCleanJunkBinding;
import com.swiftcleaner.chovey.model.bean.AppInfo;
import com.swiftcleaner.chovey.model.bean.AppInfoBean;
import com.swiftcleaner.chovey.model.tool.AppUtils;
import com.swiftcleaner.chovey.model.tool.MemoryUtils;
import com.swiftcleaner.chovey.view.adapter.AppInfoAdapter;
import com.swiftcleaner.chovey.view.adapter.AppProcessAdapter;
import com.swiftcleaner.chovey.view.dialog.CustomScoreDialog;
import java.util.ArrayList;
import java.util.List;
public class AppProcessActivity extends AppCompatActivity {
ActivityAppProcessBinding binding;
private AppProcessAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityAppProcessBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initShow();
}
private void initShow() {
binding.ivReturn.setOnClickListener(v->{
initCustDialog();
});
binding.appProcessButtonOk.setOnClickListener(v->{
initCustDialog();
});
binding.appProcessRecy.setLayoutManager(new LinearLayoutManager(this));
List<AppInfoBean> appInfoList = getNonSystemAppInfos();
adapter=new AppProcessAdapter(appInfoList,this);
binding.appProcessRecy.setAdapter(adapter);
initProcess();
}
private void initProcess() {
// 获取总内存
String totalMemory = MemoryUtils.getUsedDiskMemory(this);
// 获取当前使用内存
String usedMemory = MemoryUtils.getTotalDiskMemory(this);
String usedDiskMemoryPercent = MemoryUtils.getUsedDiskMemoryPercent(this);
binding.memoryInfoText.setText(totalMemory+"/"+usedMemory);
binding.appProcessNum.setText(usedDiskMemoryPercent);
try {
int percent = Integer.parseInt(usedDiskMemoryPercent.replaceAll("%", ""));
binding.progressBar.setProgress(percent);
} catch (NumberFormatException e) {
e.printStackTrace();
Log.e("AppProcessActivity", "Error parsing used disk memory percent: " + e.getMessage());
binding.progressBar.setProgress(0);
}
}
private List<AppInfoBean> getNonSystemAppInfos() {
PackageManager packageManager = getPackageManager();
List<ApplicationInfo> installedApps = packageManager.getInstalledApplications(0);
// 过滤掉系统应用
List<ApplicationInfo> nonSystemApps = new ArrayList<>();
for (ApplicationInfo appInfo : installedApps) {
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
nonSystemApps.add(appInfo);
}
}
// 过滤掉当前应用
List<ApplicationInfo> nonSystemAppsFiltered = new ArrayList<>();
String currentPackageName = getPackageName();
for (ApplicationInfo appInfo : nonSystemApps) {
if (!currentPackageName.equals(appInfo.packageName)) {
nonSystemAppsFiltered.add(appInfo);
}
}
// 将ApplicationInfo对象转换为AppInfoBean对象
List<AppInfoBean> apps = new ArrayList<>();
for (ApplicationInfo packageInfo : nonSystemAppsFiltered) {
String appName = packageManager.getApplicationLabel(packageInfo).toString();
Drawable appIcon = packageInfo.loadIcon(packageManager);
AppInfoBean appInfoBean = new AppInfoBean(appName, appIcon, packageInfo.packageName);
apps.add(appInfoBean);
}
return apps;
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(false) // 状态栏字体颜色为浅色
.navigationBarDarkIcon(true) // 导航栏图标颜色为浅色
.init();
}
@Override
public void onBackPressed() {
initCustDialog();
}
private void initCustDialog(){
CustomScoreDialog customScoreDialog = new CustomScoreDialog(this);
customScoreDialog.setOnDialogClickListener(new CustomScoreDialog.OnDialogClickListener() {
@Override
public void onCancel() {
customScoreDialog.dismiss();
}
@Override
public void onSubmit() {
customScoreDialog.dismiss();
finish();
}
});
customScoreDialog.show();
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Debug;
import android.view.View;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.databinding.ActivityBatteryInfoBinding;
import com.swiftcleaner.chovey.model.bean.AppInfo;
import com.swiftcleaner.chovey.model.bean.AppInfoBean;
import com.swiftcleaner.chovey.model.tool.AppUtils;
import com.swiftcleaner.chovey.view.adapter.AppInfoAdapter;
import com.swiftcleaner.chovey.view.dialog.CustomScoreDialog;
import java.util.ArrayList;
import java.util.List;
public class BatteryInfoActivity extends AppCompatActivity {
ActivityBatteryInfoBinding binding;
private AppInfoAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityBatteryInfoBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initShow();
}
private void initShow() {
PackageManager packageManager = getPackageManager();
List<ApplicationInfo> installedApps = packageManager.getInstalledApplications(0);
// 过滤掉系统应用
List<ApplicationInfo> nonSystemApps = new ArrayList<>();
for (ApplicationInfo appInfo : installedApps) {
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
nonSystemApps.add(appInfo);
}
}
// 过滤掉当前应用
List<ApplicationInfo> nonSystemAppsFiltered = new ArrayList<>();
String currentPackageName = getPackageName();
for (ApplicationInfo appInfo : nonSystemApps) {
if (!currentPackageName.equals(appInfo.packageName)) {
nonSystemAppsFiltered.add(appInfo);
}
}
// 将ApplicationInfo对象转换为AppInfoBean对象
List<AppInfoBean> apps = new ArrayList<>();
for (ApplicationInfo packageInfo : nonSystemAppsFiltered) {
String appName = packageManager.getApplicationLabel(packageInfo).toString();
Drawable appIcon = packageInfo.loadIcon(packageManager);
AppInfoBean appInfoBean = new AppInfoBean(appName, appIcon, packageInfo.packageName);
apps.add(appInfoBean);
}
binding.tvBatteryInfoNum.setText("(" + apps.size() + " in total)");
binding.batteryRecy.setLayoutManager(new LinearLayoutManager(this));
adapter = new AppInfoAdapter(apps, this);
binding.batteryRecy.setAdapter(adapter);
binding.ivReturn.setOnClickListener(v -> {
initCustDialog();
});
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(false) // 状态栏字体颜色为深色
.navigationBarDarkIcon(true) // 导航栏图标颜色为浅色
.init();
}
@Override
public void onBackPressed() {
initCustDialog();
}
private void initCustDialog(){
CustomScoreDialog customScoreDialog = new CustomScoreDialog(this);
customScoreDialog.setOnDialogClickListener(new CustomScoreDialog.OnDialogClickListener() {
@Override
public void onCancel() {
customScoreDialog.dismiss();
}
@Override
public void onSubmit() {
customScoreDialog.dismiss();
finish();
}
});
customScoreDialog.show();
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.databinding.ActivityEndCleanJunkBinding;
import com.swiftcleaner.chovey.view.dialog.CustomScoreDialog;
public class EndCleanJunkActivity extends AppCompatActivity {
ActivityEndCleanJunkBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityEndCleanJunkBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initShow();
}
private void initShow() {
Intent intent = getIntent();
String stringExtra = intent.getStringExtra("cleanstr");
binding.endCleanJunkFileNum.setText("Cleaned "+ stringExtra +" junk files");
binding.ivReturn.setOnClickListener(v->{
initCustDialog();
});
binding.buttonBatteryInfoCheckNo.setOnClickListener(v->{
startActivity(new Intent(this, InfoActivity.class));
finish();
});
binding.buttonAppManagerCheckNo.setOnClickListener(v->{
startActivity(new Intent(this, BatteryInfoActivity.class));
finish();
});
binding.buttonAppProcessCheckNo.setOnClickListener(v->{
startActivity(new Intent(this, AppProcessActivity.class));
finish();
});
binding.buttonCleanJunkCleanNo.setOnClickListener(v->{
startActivity(new Intent(this, CleanJunkActivity.class));
finish();
});
binding.buttonLargefilecleanerCleanUp.setOnClickListener(v->{
startActivity(new Intent(this, LargeFileActivity.class));
finish();
});
binding.buttonScreenshot.setOnClickListener(v->{
startActivity(new Intent(this, ScreenShotActivity.class));
finish();
});
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(false) // 状态栏字体颜色为浅色
.navigationBarDarkIcon(true) // 导航栏图标颜色为浅色
.init();
}
@Override
public void onBackPressed() {
initCustDialog();
}
private void initCustDialog(){
CustomScoreDialog customScoreDialog = new CustomScoreDialog(this);
customScoreDialog.setOnDialogClickListener(new CustomScoreDialog.OnDialogClickListener() {
@Override
public void onCancel() {
customScoreDialog.dismiss();
}
@Override
public void onSubmit() {
customScoreDialog.dismiss();
finish();
}
});
customScoreDialog.show();
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.databinding.ActivityInfoBinding;
import com.swiftcleaner.chovey.model.util.BatteryReceiver;
import com.swiftcleaner.chovey.view.dialog.CustomScoreDialog;
public class InfoActivity extends AppCompatActivity {
private ActivityInfoBinding binding;
private BatteryReceiver batteryReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityInfoBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initShow();
registerReceiver();
}
private void initBar() {
ImmersionBar.with(this).transparentStatusBar() // 透明状态栏
.statusBarDarkFont(false) // 状态栏字体颜色为浅色
.navigationBarDarkIcon(true) // 导航栏图标颜色为浅色
.init();
}
private void initShow() {
binding.ivReturn.setOnClickListener(v -> {
initCustDialog();
});
binding.infoButtonOk.setOnClickListener(v->{
initCustDialog();
});
}
private void registerReceiver() {
batteryReceiver = new BatteryReceiver(new Runnable() {
@Override
public void run() {
setBatteryInfo();
}
});
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryReceiver, intentFilter);
}
private void setBatteryInfo() {
binding.temperatureNum.setText(String.format("%.1f ℃",batteryReceiver.temperature / 10.0));
binding.voltageNum.setText(String.format("%.1f V", batteryReceiver.voltage / 1000.0));
binding.technologyNum.setText(batteryReceiver.technology);
// 格式化显示 batteryCapacityNum,保留整数
binding.batteryCapacityNum.setText(String.format("%d mAh", (int) batteryReceiver.mAh));
binding.electricNum.setText(String.format("%.2f mA", batteryReceiver.current / 1000.0));
binding.currentNum.setText(String.format("%.2f mA", batteryReceiver.currentAverage / 1000.0));
binding.infoHour.setText(String.valueOf(batteryReceiver.hours));
binding.infoMinute.setText(String.valueOf(batteryReceiver.minutes));
}
@Override
protected void onDestroy() {
super.onDestroy();
if (batteryReceiver != null) {
unregisterReceiver(batteryReceiver);
}
}
@Override
public void onBackPressed() {
initCustDialog();
}
private void initCustDialog() {
CustomScoreDialog customScoreDialog = new CustomScoreDialog(this);
customScoreDialog.setOnDialogClickListener(new CustomScoreDialog.OnDialogClickListener() {
@Override
public void onCancel() {
customScoreDialog.dismiss();
}
@Override
public void onSubmit() {
customScoreDialog.dismiss();
finish();
}
});
customScoreDialog.show();
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.databinding.ActivityScreenShotBinding;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import com.swiftcleaner.chovey.model.tool.FileHelps;
import com.swiftcleaner.chovey.model.tool.MediaHelps;
import com.swiftcleaner.chovey.model.tool.ToastUtil;
import com.swiftcleaner.chovey.view.activity.EndCleanJunkActivity;
import com.swiftcleaner.chovey.view.adapter.ScreenShotAdapter;
import com.swiftcleaner.chovey.view.dialog.CustomScoreDialog;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ScreenShotActivity extends AppCompatActivity {
private ActivityScreenShotBinding binding;
private ScreenShotAdapter screenShotAdapter;
private List<CleanFileBean> cleanFileBeans;
private Handler handler;
private ExecutorService executorService = Executors.newSingleThreadExecutor();
private long wasteNumber = 0;
private long selectedSize = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityScreenShotBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
initBar();
initShow();
}
private void initShow() {
binding.ivReturn.setOnClickListener(v -> {
initCustDialog();
});
binding.buttonScreenshotDelete.setOnClickListener(v->{
if (selectedSize==0){
ToastUtil.showLongToast(this,"请勾选要删除的文件");
}else {
showCustomDialog();
}
});
executorService.submit(() -> {
Map<String, List<CleanFileBean>> screenshotsMap = MediaHelps.findScreenshotsFiles(this);
cleanFileBeans = new ArrayList<>(screenshotsMap.values().size());
for (List<CleanFileBean> files : screenshotsMap.values()) {
for (CleanFileBean file : files) {
cleanFileBeans.add(file);
wasteNumber += file.getLength();
}
}
runOnUiThread(() -> {
screenShotAdapter = new ScreenShotAdapter(cleanFileBeans, (fileBean) -> {
if (fileBean.isSelected()) {
selectedSize += fileBean.getLength();
updateDeleteButton();
} else {
selectedSize -= fileBean.getLength();
updateDeleteButton();
}
});
binding.screenshotRecy.setLayoutManager(new GridLayoutManager(this, 3));
binding.screenshotRecy.setAdapter(screenShotAdapter);
binding.wasteNumber.setText(formatFileSize(wasteNumber));
});
});
}
private void updateDeleteButton() {
binding.buttonScreenshotDelete.setText("Delete " + formatFileSize(selectedSize));
if (selectedSize == 0) {
binding.buttonScreenshotDelete.setBackground(ContextCompat.getDrawable(this, R.drawable.shape_radio_80dp_hui_se));
} else {
binding.buttonScreenshotDelete.setBackground(ContextCompat.getDrawable(this, R.drawable.shape_clean_up));
}
}
private void showCustomDialog() {
Dialog dialog = new Dialog(this, R.style.TransparentDialogTheme);
dialog.setContentView(R.layout.dialog_delete);
AppCompatButton dialogDeleteCancel = dialog.findViewById(R.id.dialog_delete_cancel);
AppCompatButton dialogDeleteOk = dialog.findViewById(R.id.dialog_delete_ok);
CardView cardView = dialog.findViewById(R.id.cardview);
cardView.setCardBackgroundColor(Color.TRANSPARENT);
dialogDeleteCancel.setOnClickListener(v -> dialog.dismiss());
dialogDeleteOk.setOnClickListener(v -> {
List<CleanFileBean> selectedFiles = screenShotAdapter.getSelectedFiles();
cleanFiles(selectedFiles);
dialog.dismiss();
initAnimation(formatFileSize(selectedSize));
});
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
private void cleanFiles(List<CleanFileBean> selectedFiles) {
executorService.submit(() -> {
for (CleanFileBean fileBean : selectedFiles) {
FileHelps.deleteFile(fileBean.getPath());
}
runOnUiThread(() -> {
String[] paths = selectedFiles.stream()
.map(CleanFileBean::getPath)
.toArray(String[]::new);
MediaHelps.updateMedia(getApplication(), paths);
screenShotAdapter.removeSelectedFiles(selectedFiles);
screenShotAdapter.notifyDataSetChanged();
selectedSize = 0;
updateDeleteButton();
});
});
}
private void initAnimation(String cleanSize) {
binding.clRadarview.setVisibility(View.VISIBLE);
binding.clLayout.setVisibility(View.GONE);
binding.radarview.setSearching(true);
handler = new Handler(Looper.getMainLooper());
Intent intent = new Intent(this, EndCleanJunkActivity.class);
handler.postDelayed(() -> {
binding.radarview.setSearching(false);
intent.putExtra("cleanstr", cleanSize);
startActivity(intent);
finish();
}, 3000);
}
private String formatFileSize(long size) {
if (size <= 0) return "0 Bytes";
final String[] units = new String[]{"Bytes", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(false) // 状态栏字体颜色为浅色
.navigationBarDarkIcon(true) // 导航栏图标颜色为浅色
.init();
}
@Override
public void onBackPressed() {
initCustDialog();
}
private void initCustDialog() {
CustomScoreDialog customScoreDialog = new CustomScoreDialog(this);
customScoreDialog.setOnDialogClickListener(new CustomScoreDialog.OnDialogClickListener() {
@Override
public void onCancel() {
customScoreDialog.dismiss();
}
@Override
public void onSubmit() {
customScoreDialog.dismiss();
finish();
}
});
customScoreDialog.show();
}
@Override
protected void onDestroy() {
super.onDestroy();
executorService.shutdown();
if (handler != null) {
handler.removeCallbacksAndMessages(null);
}
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import androidx.cardview.widget.CardView;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.databinding.ActivityMainBinding;
import com.swiftcleaner.chovey.databinding.ActivitySettingBinding;
import com.swiftcleaner.chovey.view.dialog.CustomScoreDialog;
public class SettingActivity extends AppCompatActivity {
ActivitySettingBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySettingBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initShow();
}
private void initShow() {
binding.ivSettingReturn.setOnClickListener(v->{
initCustDialog();
});
binding.settingCl3Score.setOnClickListener(v->{
//评分弹窗
showCustomDialog();
});
binding.settingCl3Policy.setOnClickListener(v->{
Uri uri = Uri.parse("https://sites.google.com/view/swift-cleaner/swift-clean");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
});
}
private void showCustomDialog() {
Dialog dialog = new Dialog(this,R.style.TransparentDialogTheme);
dialog.setContentView(R.layout.dialog_score_item);
ImageView dialog_close = dialog.findViewById(R.id.dialog_close);
AppCompatButton dialog_submit_button = dialog.findViewById(R.id.dialog_submit_button);
CardView cardview = dialog.findViewById(R.id.cardview);
cardview.setCardBackgroundColor(Color.TRANSPARENT);
dialog_close.setOnClickListener(v->{
dialog.dismiss();
});
dialog_submit_button.setOnClickListener(v->{
dialog.dismiss();
});
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(false) // 状态栏字体颜色为浅色
.navigationBarDarkIcon(true) // 导航栏图标颜色为浅色
.init();
}
@Override
public void onBackPressed() {
initCustDialog();
}
private void initCustDialog() {
CustomScoreDialog customScoreDialog = new CustomScoreDialog(this);
customScoreDialog.setOnDialogClickListener(new CustomScoreDialog.OnDialogClickListener() {
@Override
public void onCancel() {
customScoreDialog.dismiss();
}
@Override
public void onSubmit() {
customScoreDialog.dismiss();
finish();
}
});
customScoreDialog.show();
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.os.Bundle;
import android.view.View;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.databinding.ActivitySimilarPhotosBinding;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import com.swiftcleaner.chovey.model.bean.SimilarBean;
import com.swiftcleaner.chovey.model.bean.ImageHelpers;
import com.swiftcleaner.chovey.model.tool.MediaHelps;
import com.swiftcleaner.chovey.view.adapter.SimilarPhotosAdapter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SimilarPhotosActivity extends AppCompatActivity {
private ExecutorService executorService = Executors.newSingleThreadExecutor();
private Semaphore semaphore = new Semaphore(10); // 限制并发数
ActivitySimilarPhotosBinding binding;
SimilarPhotosAdapter similarPhotosAdapter;
private long selectedSize = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySimilarPhotosBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initShow();
}
private void initShow() {
binding.ivReturn.setOnClickListener(v -> {
finish();
});
initSimilar();
}
private List<SimilarBean> groupSimilarImages(List<SimilarBean> similarBeans) {
Set<String> hasSame = new HashSet<>();
List<SimilarBean> groupedBeans = new ArrayList<>();
for (SimilarBean similar : similarBeans) {
if (!hasSame.contains(similar.getUrl())) {
hasSame.add(similar.getUrl());
similar.getItems().add(similar);
for (SimilarBean other : similarBeans) {
if (!hasSame.contains(other.getUrl()) && ImageHelpers.similarCondition(similar, other)) {
hasSame.add(other.getUrl());
similar.getItems().add(other);
}
}
groupedBeans.add(similar);
}
}
return groupedBeans;
}
private void initSimilar() {
executorService.submit(() -> {
List<CleanFileBean> images = MediaHelps.findImageFiles(this, 0);
List<SimilarBean> similarBeans = new ArrayList<>();
for (CleanFileBean image : images) {
try {
semaphore.acquire();
SimilarBean bean = ImageHelpers.createImage(image.getPath());
if (bean != null) {
similarBeans.add(bean);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
List<SimilarBean> groupedBeans = groupSimilarImages(similarBeans);
runOnUiThread(() -> {
// progressBar.setVisibility(android.view.View.GONE);
similarPhotosAdapter = new SimilarPhotosAdapter(groupedBeans, new SimilarPhotosAdapter.OnItemClickListener() {
@Override
public void onItemClick(CleanFileBean fileBean) {
}
});
binding.similarPhotosRecy.setAdapter(similarPhotosAdapter);
binding.similarPhotosRecy.setLayoutManager(new LinearLayoutManager(this));
});
// List<CleanFileBean> imageFiles = MediaHelps.findImageFiles(this, 0);
//
// // 异步获取相似图片
// List<SimilarBean> similarBeans = imageFiles.stream()
// .map(value -> {
// try {
// semaphore.acquire();
// try {
// return ImageHelpers.createImage(value.getPath());
// } finally {
// semaphore.release();
// }
// } catch (InterruptedException e) {
// e.printStackTrace();
// return null;
// }
// })
// .filter(Objects::nonNull)
// .collect(Collectors.toList());
//
// // 处理相似图片逻辑
// Set<String> hasSame = new HashSet<>();
// for (SimilarBean similar : similarBeans) {
// if (hasSame.contains(similar.getUrl())) continue;
// hasSame.add(similar.getUrl());
// similar.getItems().add(similar);
// for (SimilarBean it : similarBeans) {
// if (!hasSame.contains(it.getUrl()) && ImageHelpers.similarCondition(similar, it)) {
// hasSame.add(it.getUrl());
// similar.getItems().add(it);
// }
// }
// }
//
// // 过滤出相似图片集合
// List<SimilarBean> list = similarBeans.stream()
// .filter(bean -> bean.getItems().size() > 1)
// .collect(Collectors.toList());
//
// runOnUiThread(() -> {
//
// similarPhotosAdapter = new SimilarPhotosAdapter(list, new SimilarPhotosAdapter.OnItemClickListener() {
// @Override
// public void onItemClick(CleanFileBean fileBean) {
// if (fileBean.isSelected()) {
// selectedSize += fileBean.getLength();
// updateButtonStatus();
// } else {
// selectedSize -= fileBean.getLength();
// updateButtonStatus();
// }
// }
// });
// binding.similarPhotosRecy.setAdapter(similarPhotosAdapter);
// binding.similarPhotosRecy.setLayoutManager(new LinearLayoutManager(this));
// });
//
// // 关闭线程池
// executorService.shutdown();
// try {
// executorService.awaitTermination(1, TimeUnit.MINUTES);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
});
}
private void updateButtonStatus() {
// binding.buttonCleanUp.setText("Clean Up " + formatFileSize(selectedSize));
//// if (selectedSize == 0) {
//// binding.buttonCleanUp.setBackground(ContextCompat.getDrawable(this, R.drawable.shape_radio_80dp_hui_se));
//// } else {
//// binding.buttonCleanUp.setBackground(ContextCompat.getDrawable(this, R.drawable.shape_clean_up));
//// }
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(false) // 状态栏字体颜色为浅色
.navigationBarDarkIcon(true) // 导航栏图标颜色为浅色
.init();
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.animation.Animator;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.databinding.ActivityStartBinding;
import com.swiftcleaner.chovey.model.util.PermissionUtils;
import com.swiftcleaner.chovey.view.MainActivity;
public class StartActivity extends AppCompatActivity {
private ActivityResultLauncher<String> requestNotificationPermissionLauncher;
ActivityStartBinding binding;
private SharedPreferences sharedPreferences;
private ActivityResultLauncher<String[]> multiplePermissionsLauncher;
private ActivityResultLauncher<Intent> notificationSettingsLauncher;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityStartBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initPermission();
sharedPreferences = getSharedPreferences("AppPreferences", MODE_PRIVATE);
boolean isFirstTime = sharedPreferences.getBoolean("isFirstTime", true);
if (!isFirstTime) {
//点击过start
binding.startId.setVisibility(View.GONE);
binding.llAgreement.setVisibility(View.GONE);
binding.lottieAnimattionView.setVisibility(View.VISIBLE);
startAnimation();
} else {
//未点击start
setupStartButton();
//协议
setupAgreementTextView();
}
}
private void initPermission() {
multiplePermissionsLauncher = registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(),
result -> {
if (result.get(Manifest.permission.POST_NOTIFICATIONS) != null && result.get(Manifest.permission.POST_NOTIFICATIONS)) {
permissionGranted();
}
}
);
// 初始化通知设置启动器
notificationSettingsLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
// 处理结果
}
);
// 请求通知权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
PermissionUtils.requestNotificationPermission(this, notificationSettingsLauncher, multiplePermissionsLauncher);
}
}
private void permissionGranted() {
// 处理权限被授予的情况
}
//启动动画
private void startAnimation() {
binding.lottieAnimattionView.setAnimation(R.raw.sp_anim);
// 播放动画
binding.lottieAnimattionView.playAnimation();
// 暂停动画
// lottieAnimationView.pauseAnimation();
// 停止动画
// lottieAnimationView.cancelAnimation();
binding.lottieAnimattionView.addAnimatorListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(@NonNull Animator animator) {
// 动画开始时调用 初始化广告
initializeThirdPartySDKsAndUserData();
}
@Override
public void onAnimationEnd(@NonNull Animator animator) {
// 动画结束时调用 动画结束后跳转首页
goToMainActivity();
}
@Override
public void onAnimationCancel(@NonNull Animator animator) {
// 动画被取消时调用
}
@Override
public void onAnimationRepeat(@NonNull Animator animator) {
// 动画重复时调用
}
});
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(true) // 状态栏字体颜色为深色
.navigationBarDarkIcon(false) // 导航栏图标颜色为浅色
.init();
}
private void setupStartButton() {
binding.startId.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean("isFirstTime", false);
editor.apply();
//加载动画
binding.startId.setVisibility(View.GONE);
binding.llAgreement.setVisibility(View.GONE);
binding.lottieAnimattionView.setVisibility(View.VISIBLE);
startAnimation();
}
});
}
private void initializeThirdPartySDKsAndUserData() {
// 在这里执行第三方 SDK 的初始化和其他数据读取操作
}
private void setupAgreementTextView() {
binding.userAgreement.setOnClickListener(v->{
Uri uri = Uri.parse("https://sites.google.com/view/terms-swf/terms");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
});
binding.privacyPolicy.setOnClickListener(v->{
Uri uri = Uri.parse("https://sites.google.com/view/swift-cleaner/swift-clean");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
});
}
private void goToMainActivity() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (binding.lottieAnimattionView != null) {
binding.lottieAnimattionView.cancelAnimation(); // 停止动画
binding.lottieAnimattionView.clearAnimation(); // 清除动画
binding.lottieAnimattionView.setImageDrawable(null); // 清除图像
binding.lottieAnimattionView.destroyDrawingCache(); // 销毁缓存
}
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.gyf.immersionbar.ImmersionBar;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.databinding.ActivityStartBinding;
import com.swiftcleaner.chovey.databinding.ActivityWhatsAppBinding;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import com.swiftcleaner.chovey.model.tool.FileHelps;
import com.swiftcleaner.chovey.model.tool.FileTypes;
import com.swiftcleaner.chovey.view.adapter.EmptyCleanAdapter;
import com.swiftcleaner.chovey.view.adapter.WhatsAppCleanAdapter;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
public class WhatsAppActivity extends AppCompatActivity {
ActivityWhatsAppBinding binding;
// List<CleanFileBean> cleanFileList;
WhatsAppCleanAdapter whatsAppCleanAdapter;
public long totalSelectedSize = 0;
private long selectedSize = 0;
List<CleanFileBean> videoList;
List<CleanFileBean> imageList;
List<CleanFileBean> audioList;
private ExecutorService executorService = Executors.newSingleThreadExecutor();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityWhatsAppBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
initBar();
initShow();
}
private void initShow() {
executorService.submit(() -> {
List<CleanFileBean> files = FileHelps.findWhatsappFiles();
Log.d("ssad",files.toString());
if (files!=null){
videoList = files.stream()
.filter(file -> FileTypes.videos.stream().anyMatch(suffix -> file.getName().toLowerCase(Locale.ROOT).endsWith(suffix)))
.collect(Collectors.toList());
imageList = files.stream()
.filter(file -> FileTypes.images.stream().anyMatch(suffix -> file.getName().toLowerCase(Locale.ROOT).endsWith(suffix)))
.collect(Collectors.toList());
audioList = files.stream()
.filter(file -> FileTypes.audios.stream().anyMatch(suffix -> file.getName().toLowerCase(Locale.ROOT).endsWith(suffix)))
.collect(Collectors.toList());
}
// if (videoList != null) {
// for (CleanFileBean file : videoList) {
// if (file.getMineType() != null && file.getName() != null) {
// file.setSelected(true); // 设置为选中状态
// cleanFileList.add(file);
// totalSelectedSize += file.getLength();
// selectedSize += file.getLength(); // 更新 selectedSize
// }
// }
// }
// if (imageList != null) {
// for (CleanFileBean file : imageList) {
// if (file.getMineType() != null && file.getName() != null) {
// file.setSelected(true); // 设置为选中状态
// cleanFileList.add(file);
// totalSelectedSize += file.getLength();
// selectedSize += file.getLength(); // 更新 selectedSize
// }
// }
// }
// if (audioList != null) {
// for (CleanFileBean file : audioList) {
// if (file.getMineType() != null && file.getName() != null) {
// file.setSelected(true); // 设置为选中状态
// cleanFileList.add(file);
// totalSelectedSize += file.getLength();
// selectedSize += file.getLength(); // 更新 selectedSize
// }
// }
// }
runOnUiThread(() -> {
whatsAppCleanAdapter = new WhatsAppCleanAdapter(imageList, new WhatsAppCleanAdapter.OnItemClickListener() {
@Override
public void onItemClick(CleanFileBean fileBean) {
if (fileBean.isSelected()) {
selectedSize += fileBean.getLength();
updateButtonStatus();
} else {
selectedSize -= fileBean.getLength();
updateButtonStatus();
}
}
});
binding.imageFilesRecy.setAdapter(whatsAppCleanAdapter);
binding.imageFilesRecy.setLayoutManager(new LinearLayoutManager(this));
binding.wasteNumber.setText(formatFileSize(totalSelectedSize));
});
});
}
private void updateButtonStatus() {
binding.buttonCleanUp.setText("Clean Up " + formatFileSize(selectedSize));
}
private String formatFileSize(long size) {
if (size <= 0) return "0 Bytes";
final String[] units = new String[]{"Bytes", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
private void initBar() {
ImmersionBar.with(this)
.transparentStatusBar() // 透明状态栏
.statusBarDarkFont(true) // 状态栏字体颜色为深色
.navigationBarDarkIcon(false) // 导航栏图标颜色为浅色
.init();
}
}
\ No newline at end of file
package com.swiftcleaner.chovey.view.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
public class ApkCleanAdapter extends RecyclerView.Adapter<ApkCleanAdapter.AppInfoViewHolder> {
private List<CleanFileBean> list;
private OnItemClickListener listener;
public ApkCleanAdapter(List<CleanFileBean> list, OnItemClickListener listener) {
this.list = list;
this.listener = listener;
}
@NonNull
@Override
public AppInfoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_clean_list_min, parent, false);
return new AppInfoViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull AppInfoViewHolder holder, int position) {
CleanFileBean fileInfo = list.get(position);
if (fileInfo!=null&&fileInfo.getPath()!=null){
Glide.with(holder.itemView.getContext())
.load(R.mipmap.l_apk)
.apply(new RequestOptions().transform(new RoundedCorners(10)))
.error(R.mipmap.ic_launcher)
.placeholder(R.mipmap.ic_launcher)
.into(holder.apk_icon);
holder.apk_Name.setText(fileInfo.getName());
holder.apk_number.setText(formatFileSize(fileInfo.getLength()));
holder.apk_checked.setChecked(fileInfo.isSelected());
holder.itemView.setOnClickListener(v -> {
// 切换选中状态
fileInfo.setSelected(!fileInfo.isSelected());
// 通知数据变化,更新视图
notifyItemChanged(position);
// 如果设置了点击事件监听器,则回调
if (listener != null) {
listener.onItemClick(fileInfo);
}
});
}
}
private String formatFileSize(long size) {
if (size <= 0) return "0 Bytes";
final String[] units = new String[]{"Bytes", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
@Override
public int getItemCount() {
return list.size();
}
public List<CleanFileBean> getSelectedFiles() {
List<CleanFileBean> selectedFiles = new ArrayList<>();
for (CleanFileBean fileBean : list) {
if (fileBean.isSelected()) {
selectedFiles.add(fileBean);
}
}
return selectedFiles;
}
public void removeSelectedFiles(List<CleanFileBean> selectedFiles) {
list.removeAll(selectedFiles);
notifyDataSetChanged(); // 通知适配器数据已更改
}
public void setAllChecked(boolean isChecked) {
for (CleanFileBean fileBean : list) {
fileBean.setSelected(isChecked);
}
notifyDataSetChanged(); // 通知适配器数据已更改
}
public boolean isAllChecked() {
for (CleanFileBean fileBean : list) {
if (!fileBean.isSelected()) {
return false;
}
}
return true;
}
public static class AppInfoViewHolder extends RecyclerView.ViewHolder {
ImageView apk_icon;
TextView apk_Name, apk_number;
CheckBox apk_checked;
public AppInfoViewHolder(@NonNull View itemView) {
super(itemView);
apk_icon = itemView.findViewById(R.id.item_clean_list_file_img);
apk_Name = itemView.findViewById(R.id.item_clean_list_file_name);
apk_checked = itemView.findViewById(R.id.item_clean_list_file_checkout);
apk_number = itemView.findViewById(R.id.item_clean_list_file_number);
}
}
public interface OnItemClickListener {
void onItemClick(CleanFileBean fileBean);
}
}
package com.swiftcleaner.chovey.view.adapter;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatButton;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.model.bean.AppInfo;
import com.swiftcleaner.chovey.model.bean.AppInfoBean;
import java.util.List;
public class AppInfoAdapter extends RecyclerView.Adapter<AppInfoAdapter.AppInfoViewHolder> {
private List<AppInfoBean> appList;
Context context;
public AppInfoAdapter(List<AppInfoBean> appList, Context context) {
this.appList = appList;
this.context = context;
}
@NonNull
@Override
public AppInfoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_battery_list, parent, false);
return new AppInfoViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull AppInfoViewHolder holder, int position) {
AppInfoBean appInfoBean = appList.get(position);
holder.button_delete.setOnClickListener(v->{
// 卸载应用
Intent intentUninstall = new Intent(Intent.ACTION_DELETE);
intentUninstall.setData(Uri.parse("package:" + appInfoBean.getPackageName()));
context.startActivity(intentUninstall);
notifyDataSetChanged();
});
Glide.with(context)
.load(appInfoBean.getAppIcon())
.apply(new RequestOptions().transform(new RoundedCorners(10)))
.error(R.mipmap.ic_launcher)
.placeholder(R.mipmap.ic_launcher)
.into(holder.icon);
holder.appName.setText(appInfoBean.getAppName());
// holder.memoryUsage.setText(String.format("", formatMemoryUsage(appInfoBean.)));
}
@Override
public int getItemCount() {
return appList.size();
}
public static class AppInfoViewHolder extends RecyclerView.ViewHolder {
ImageView icon;
TextView appName;
TextView memoryUsage;
AppCompatButton button_delete;
public AppInfoViewHolder(@NonNull View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.item_battery_img);
appName = itemView.findViewById(R.id.item_battery_name);
memoryUsage = itemView.findViewById(R.id.item_battery_memory_number);
button_delete = itemView.findViewById(R.id.item_button_battery_delete);
}
}
}
package com.swiftcleaner.chovey.view.adapter;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatButton;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.model.bean.AppInfo;
import com.swiftcleaner.chovey.model.bean.AppInfoBean;
import java.util.List;
public class AppProcessAdapter extends RecyclerView.Adapter<AppProcessAdapter.AppInfoViewHolder> {
private List<AppInfoBean> appList;
Context context;
public AppProcessAdapter(List<AppInfoBean> appList, Context context) {
this.appList = appList;
this.context = context;
}
@NonNull
@Override
public AppInfoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_process_list, parent, false);
return new AppInfoViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull AppInfoViewHolder holder, int position) {
AppInfoBean appInfo = appList.get(position);
holder.button_delete.setOnClickListener(v->{
// 打开应用详情页(进程)
Intent intentAppDetails = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intentAppDetails.setData(Uri.parse("package:" + appInfo.getPackageName()));
context.startActivity(intentAppDetails);
});
Glide.with(context)
.load(appInfo.getAppIcon())
.apply(new RequestOptions().transform(new RoundedCorners(10)))
.error(R.mipmap.ic_launcher)
.placeholder(R.mipmap.ic_launcher)
.into(holder.icon);
holder.appName.setText(appInfo.getAppName());
}
@Override
public int getItemCount() {
return appList.size();
}
public static class AppInfoViewHolder extends RecyclerView.ViewHolder {
ImageView icon;
TextView appName;
AppCompatButton button_delete;
public AppInfoViewHolder(@NonNull View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.item_battery_img);
appName = itemView.findViewById(R.id.item_battery_name);
button_delete = itemView.findViewById(R.id.item_button_battery_delete);
}
}
}
package com.swiftcleaner.chovey.view.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
public class EmptyCleanAdapter extends RecyclerView.Adapter<EmptyCleanAdapter.AppInfoViewHolder> {
private List<CleanFileBean> list;
private OnItemClickListener listener;
public EmptyCleanAdapter(List<CleanFileBean> list, OnItemClickListener listener) {
this.list = list;
this.listener = listener;
}
@NonNull
@Override
public AppInfoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_clean_list_min, parent, false);
return new AppInfoViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull AppInfoViewHolder holder, int position) {
CleanFileBean fileInfo = list.get(position);
if (fileInfo!=null&&fileInfo.getPath()!=null){
Glide.with(holder.itemView.getContext())
.load(R.mipmap.l_apk)
.apply(new RequestOptions().transform(new RoundedCorners(10)))
.error(R.mipmap.ic_launcher)
.placeholder(R.mipmap.ic_launcher)
.into(holder.apk_icon);
holder.apk_Name.setText(fileInfo.getName());
holder.apk_number.setText(formatFileSize(fileInfo.getLength()));
holder.apk_checked.setChecked(fileInfo.isSelected());
holder.itemView.setOnClickListener(v -> {
// 切换选中状态
fileInfo.setSelected(!fileInfo.isSelected());
// 通知数据变化,更新视图
notifyItemChanged(position);
// 如果设置了点击事件监听器,则回调
if (listener != null) {
listener.onItemClick(fileInfo);
}
});
}
}
private String formatFileSize(long size) {
if (size <= 0) return "0 Bytes";
final String[] units = new String[]{"Bytes", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
@Override
public int getItemCount() {
return list.size();
}
public List<CleanFileBean> getSelectedFiles() {
List<CleanFileBean> selectedFiles = new ArrayList<>();
for (CleanFileBean fileBean : list) {
if (fileBean.isSelected()) {
selectedFiles.add(fileBean);
}
}
return selectedFiles;
}
public void removeSelectedFiles(List<CleanFileBean> selectedFiles) {
list.removeAll(selectedFiles);
notifyDataSetChanged(); // 通知适配器数据已更改
}
public void setAllChecked(boolean isChecked) {
for (CleanFileBean fileBean : list) {
fileBean.setSelected(isChecked);
}
notifyDataSetChanged(); // 通知适配器数据已更改
}
public boolean isAllChecked() {
for (CleanFileBean fileBean : list) {
if (!fileBean.isSelected()) {
return false;
}
}
return true;
}
public static class AppInfoViewHolder extends RecyclerView.ViewHolder {
ImageView apk_icon;
TextView apk_Name, apk_number;
CheckBox apk_checked;
public AppInfoViewHolder(@NonNull View itemView) {
super(itemView);
apk_icon = itemView.findViewById(R.id.item_clean_list_file_img);
apk_Name = itemView.findViewById(R.id.item_clean_list_file_name);
apk_checked = itemView.findViewById(R.id.item_clean_list_file_checkout);
apk_number = itemView.findViewById(R.id.item_clean_list_file_number);
}
}
public interface OnItemClickListener {
void onItemClick(CleanFileBean fileBean);
}
}
package com.swiftcleaner.chovey.view.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import com.swiftcleaner.chovey.model.bean.SimilarBean;
import java.util.List;
/**
* 作者:马海钊
* 时间:2024/12/18 14:05
* 功能:
*/
public class ItemSimilarPhotosAdapter extends BaseAdapter {
private Context context;
private List<SimilarBean> childItems;
public ItemSimilarPhotosAdapter(Context context, List<SimilarBean> childItems) {
this.context = context;
this.childItems = childItems;
}
@Override
public int getCount() {
return childItems.size();
}
@Override
public Object getItem(int position) {
return childItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.item_screen_shot_list, parent, false);
holder = new ViewHolder();
holder.childItemText = view.findViewById(R.id.item_screen_shot_number);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
if (childItems!=null){
// Glide.with(context).load(R.mipmap.l_tu).error(R.mipmap.err_img).into(holder.img);
// holder.childItemText.setText(""+childItems.get(position).getSize());
}
return view;
}
private static class ViewHolder {
TextView childItemText;
CheckBox checkBox;
ImageView img;
}
}
package com.swiftcleaner.chovey.view.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.swiftcleaner.chovey.R;
import com.swiftcleaner.chovey.model.bean.CleanFileBean;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
public class LargeFileAdapter extends RecyclerView.Adapter<LargeFileAdapter.ViewHolder> {
List<CleanFileBean> list;
private OnItemClickListener listener;
public LargeFileAdapter(List<CleanFileBean> list, OnItemClickListener listener) {
this.list = list;
this.listener=listener;
}
public void removeSelectedFiles(List<CleanFileBean> selectedFiles) {
list.removeAll(selectedFiles);
notifyDataSetChanged(); // 通知适配器数据已更改
}
public interface OnItemClickListener {
void onItemClick(CleanFileBean fileBean);
}
@NonNull
@Override
public LargeFileAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_larage_file_list, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull LargeFileAdapter.ViewHolder holder, int position) {
CleanFileBean fileInfo = list.get(position);
if (fileInfo.getPath()!=null){
holder.name.setText(fileInfo.getName());
holder.size.setText(formatFileSize(fileInfo.getLength()));
// 根据文件类型设置不同的图标或背景等
if (isImageFile(fileInfo)) {
Glide.with(holder.itemView.getContext())
.asBitmap()
.load(R.mipmap.l_other)
.placeholder(R.mipmap.h_appmanager)
.error(R.mipmap.l_other)
.apply(RequestOptions.bitmapTransform(new RoundedCorners(20)))
.into(holder.img);
// 设置图片图标或背景
} else if (isVideoFile(fileInfo)) {
Glide.with(holder.itemView.getContext())
.asBitmap()
.load(R.mipmap.l_tu)
.placeholder(R.mipmap.h_appmanager)
.error(R.mipmap.l_tu)
.apply(RequestOptions.bitmapTransform(new RoundedCorners(20)))
.into(holder.img);
// 设置视频图标或背景
} else if (isAudioFile(fileInfo)) {
Glide.with(holder.itemView.getContext())
.asBitmap()
.load(R.mipmap.l_shipin)
.placeholder(R.mipmap.h_appmanager)
.error(R.mipmap.l_shipin)
.apply(RequestOptions.bitmapTransform(new RoundedCorners(20)))
.into(holder.img);
// 设置音频图标或背景
} else if (isDocFile(fileInfo)) {
Glide.with(holder.itemView.getContext())
.asBitmap()
.load(R.mipmap.w_audio)
.placeholder(R.mipmap.h_appmanager)
.error(R.mipmap.w_audio)
.apply(RequestOptions.bitmapTransform(new RoundedCorners(20)))
.into(holder.img);
// 设置文档图标或背景
} else if (isApkFile(fileInfo)) {
Glide.with(holder.itemView.getContext())
.asBitmap()
.load(R.mipmap.l_doc)
.placeholder(R.mipmap.h_appmanager)
.error(R.mipmap.l_doc)
.apply(RequestOptions.bitmapTransform(new RoundedCorners(20)))
.into(holder.img);
// 设置 APK 图标或背景
} else {
// 设置其他类型的图标或背景
Glide.with(holder.itemView.getContext())
.asBitmap()
.load(R.mipmap.l_apk)
.placeholder(R.mipmap.h_appmanager)
.error(R.mipmap.l_apk)
.apply(RequestOptions.bitmapTransform(new RoundedCorners(20)))
.into(holder.img);
}
}
holder.checkBox.setChecked(fileInfo.isSelected());
holder.itemView.setOnClickListener(v -> {
// 切换选中状态
fileInfo.setSelected(!fileInfo.isSelected());
// 通知数据变化,更新视图
notifyItemChanged(position);
// 如果设置了点击事件监听器,则回调
if (listener != null) {
listener.onItemClick(fileInfo);
}
});
}
public List<CleanFileBean> getSelectedFiles() {
List<CleanFileBean> selectedFiles = new ArrayList<>();
for (CleanFileBean fileBean : list) {
if (fileBean.isSelected()) {
selectedFiles.add(fileBean);
}
}
return selectedFiles;
}
@Override
public int getItemCount() {
return list.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView name, size;
ImageView img;
CheckBox checkBox;
public ViewHolder(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.item_large_file_list_name);
size = itemView.findViewById(R.id.item_large_file_list_size);
img = itemView.findViewById(R.id.item_large_file_list_img);
checkBox = itemView.findViewById(R.id.item_large_file_list_checked);
}
}
private static String formatFileSize(long size) {
if (size <= 0) return "0 Bytes";
final String[] units = new String[]{"Bytes", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
private boolean isImageFile(CleanFileBean file) {
// 判断 CleanFileBean 是否代表图片文件
String mimeType = file.getMineType();
return mimeType!= null && mimeType.startsWith("image/");
}
private boolean isVideoFile(CleanFileBean file) {
// 判断 CleanFileBean 是否代表视频文件
String mimeType = file.getMineType();
return mimeType!= null && mimeType.startsWith("video/");
}
private boolean isAudioFile(CleanFileBean file) {
// 判断 CleanFileBean 是否代表音频文件
String mimeType = file.getMineType();
return mimeType!= null && mimeType.startsWith("audio/");
}
private boolean isDocFile(CleanFileBean file) {
// 判断 CleanFileBean 是否代表文档文件
String mimeType = file.getMineType();
return mimeType!= null && (mimeType.equals("text/plain") ||
mimeType.equals("application/msword") ||
mimeType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document") ||
mimeType.equals("application/vnd.ms-excel") ||
mimeType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") ||
mimeType.equals("application/pdf"));
}
private boolean isApkFile(CleanFileBean file) {
// 判断 CleanFileBean 是否代表 APK 文件
String fileName = file.getName();
return fileName!= null && (fileName.endsWith(".apk") || fileName.endsWith(".aab"));
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@mipmap/gouxuan"/>
<item android:state_checked="false" android:drawable="@mipmap/weixuan"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@mipmap/s_xuan"/>
<item android:state_checked="false" android:drawable="@mipmap/s_weixuan"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@mipmap/selectall_s"/>
<item android:state_checked="false" android:drawable="@mipmap/selectall_n"/>
</selector>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/on" android:state_selected="true" />
<item android:drawable="@mipmap/off" android:state_selected="false" />
</selector>
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="270"
android:startColor="#1EAAFD"
android:endColor="#3173F5"
android:type="linear" />
</shape>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment