Commit b37d8503 authored by wanglei's avatar wanglei

...

parent aaf76cdb
package com.base.browserwhite.ui.activity.cleanjunk package com.base.browserwhite.ui.activity.cleanjunk
import android.graphics.Color import android.graphics.Color
import android.os.Environment
import android.view.View
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.base.browserwhite.R import com.base.browserwhite.R
...@@ -9,9 +11,17 @@ import com.base.browserwhite.databinding.ActivityScanJunkBinding ...@@ -9,9 +11,17 @@ import com.base.browserwhite.databinding.ActivityScanJunkBinding
import com.base.browserwhite.ui.activity.BaseActivity import com.base.browserwhite.ui.activity.BaseActivity
import com.base.browserwhite.ui.adapter.JunkScanAdapter import com.base.browserwhite.ui.adapter.JunkScanAdapter
import com.base.browserwhite.utils.BarUtils import com.base.browserwhite.utils.BarUtils
import com.base.browserwhite.utils.FileHelp.getFileFolder
import com.base.browserwhite.utils.KotlinExt.toFormatSize
import com.base.browserwhite.utils.MediaStoreUtils.queryFiles
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File
class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() { class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() {
...@@ -20,6 +30,12 @@ class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() { ...@@ -20,6 +30,12 @@ class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() {
override val binding: ActivityScanJunkBinding by lazy { override val binding: ActivityScanJunkBinding by lazy {
ActivityScanJunkBinding.inflate(layoutInflater) ActivityScanJunkBinding.inflate(layoutInflater)
} }
private val mPathFlow = MutableSharedFlow<String>(
replay = 5,//当新的订阅者Collect时,发送几个已经发送过的数据给它
extraBufferCapacity = 5,//减去replay,MutableSharedFlow还缓存多少数据,缓冲池容量 = replay + extraBufferCapacity
onBufferOverflow = BufferOverflow.DROP_OLDEST//缓存策略,三种 丢掉最新值、丢掉最旧值和挂起
)
val pathFlow: SharedFlow<String> = mPathFlow
override fun initView() { override fun initView() {
BarUtils.setStatusBarLightMode(this, true) BarUtils.setStatusBarLightMode(this, true)
...@@ -30,6 +46,12 @@ class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() { ...@@ -30,6 +46,12 @@ class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() {
junkScanAdapter = JunkScanAdapter() junkScanAdapter = JunkScanAdapter()
binding.rv.adapter = junkScanAdapter binding.rv.adapter = junkScanAdapter
lifecycleScope.launch(Dispatchers.Main) {
pathFlow.collectLatest {
binding.tvPath.text = it
}
}
beginScan() beginScan()
} }
...@@ -45,8 +67,8 @@ class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() { ...@@ -45,8 +67,8 @@ class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() {
} }
private fun beginScan() { private fun beginScan() = lifecycleScope.launch(Dispatchers.Main) {
lifecycleScope.launch(Dispatchers.Main) { var size = 0L
junkScanAdapter.addData(ParentBean(R.mipmap.x_residual, "Residual File"), 0) junkScanAdapter.addData(ParentBean(R.mipmap.x_residual, "Residual File"), 0)
delay(300) delay(300)
junkScanAdapter.addData(ParentBean(R.mipmap.x_useless, "Useless installation package"), 1) junkScanAdapter.addData(ParentBean(R.mipmap.x_useless, "Useless installation package"), 1)
...@@ -55,9 +77,45 @@ class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() { ...@@ -55,9 +77,45 @@ class ScanJunkActivity : BaseActivity<ActivityScanJunkBinding>() {
delay(300) delay(300)
junkScanAdapter.addData(ParentBean(R.mipmap.x_residual, "Log Files"), 3) junkScanAdapter.addData(ParentBean(R.mipmap.x_residual, "Log Files"), 3)
val emptyFolder = arrayListOf<File>()
arrayOf(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS),
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC),
).forEach { dir ->
val list = getFileFolder(mPathFlow, dir, filter = { it.listFiles().isNullOrEmpty() }).await()
emptyFolder.addAll(list)
}
size = emptyFolder.sumOf { it.length() }
setSize(size)
junkScanAdapter.setFinishScan(0)
val apkList = queryFiles(this@ScanJunkActivity, ".apk", mPathFlow).await()
size += apkList.sumOf { it.length() }
setSize(size)
junkScanAdapter.setFinishScan(1)
val tempList = queryFiles(this@ScanJunkActivity, ".temp", mPathFlow).await()
size += tempList.sumOf { it.length() }
setSize(size)
junkScanAdapter.setFinishScan(2)
val logList = queryFiles(this@ScanJunkActivity, ".log", mPathFlow).await()
size += logList.sumOf { it.length() }
setSize(size)
junkScanAdapter.setFinishScan(3)
binding.tvPath.visibility = View.GONE
binding.tvBtn.isEnabled=true
} }
private fun setSize(size: Long) {
val split = size.toFormatSize().split(" ")
binding.tvSize.text = split[0]
binding.tvUnit.text = split[1]
} }
......
...@@ -64,5 +64,11 @@ class JunkScanAdapter : RecyclerView.Adapter<JunkScanAdapter.ParentViewHolder>() ...@@ -64,5 +64,11 @@ class JunkScanAdapter : RecyclerView.Adapter<JunkScanAdapter.ParentViewHolder>()
notifyItemChanged(position) notifyItemChanged(position)
} }
fun setFinishScan(position: Int) {
val bean = beanList[position]
bean.finished = true
notifyItemChanged(position)
}
} }
\ No newline at end of file
package com.base.browserwhite.utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableSharedFlow
import java.io.File
import java.util.LinkedList
object FileHelp {
fun CoroutineScope.getFileFolder(
flow: MutableSharedFlow<String>,
file: File,
filter: (file: File) -> Boolean
) = async(Dispatchers.IO) {
val set = HashSet<File>()
//添加第一层文件到链表
val linkList = LinkedList<File>()
val fileList = file.listFiles()
fileList?.forEach {
if (it.isDirectory) {
flow.emit(it.absolutePath)
linkList.add(it)
if (filter.invoke(it)) {
set.add(it)
}
}
}
//链表取文件
var tempFile: File
while (!linkList.isEmpty()) {
tempFile = linkList.removeFirst()
val tempFileList = tempFile.listFiles()
tempFileList?.forEach {
if (it.isDirectory) {
flow.emit(it.absolutePath)
linkList.add(it)
if (filter.invoke(it)) {
set.add(it)
}
}
}
}
set.toList()
}
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ package com.base.browserwhite.utils ...@@ -3,6 +3,7 @@ package com.base.browserwhite.utils
import android.content.Context import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.os.Build
import android.provider.MediaStore import android.provider.MediaStore
import com.base.browserwhite.bean.ConstObject.MIME_TYPE_APK import com.base.browserwhite.bean.ConstObject.MIME_TYPE_APK
import com.base.browserwhite.bean.ConstObject.MIME_TYPE_AUDIO import com.base.browserwhite.bean.ConstObject.MIME_TYPE_AUDIO
...@@ -17,6 +18,12 @@ import com.base.browserwhite.bean.ConstObject.MIME_TYPE_XLS ...@@ -17,6 +18,12 @@ import com.base.browserwhite.bean.ConstObject.MIME_TYPE_XLS
import com.base.browserwhite.bean.ConstObject.MIME_TYPE_XLSX import com.base.browserwhite.bean.ConstObject.MIME_TYPE_XLSX
import com.base.browserwhite.bean.ConstObject.MIME_TYPE_ZIP import com.base.browserwhite.bean.ConstObject.MIME_TYPE_ZIP
import com.base.browserwhite.bean.MediaBean import com.base.browserwhite.bean.MediaBean
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import java.io.File
object MediaStoreUtils { object MediaStoreUtils {
...@@ -351,4 +358,37 @@ object MediaStoreUtils { ...@@ -351,4 +358,37 @@ object MediaStoreUtils {
} }
return count return count
} }
private fun getFileTypeSelection(fileSuffix: String): String {
return (MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_NONE + " AND "
+ MediaStore.Files.FileColumns.DATA + " LIKE '%" + fileSuffix + "'")
}
fun CoroutineScope.queryFiles(context: Context, fileSuffix: String, flow: MutableSharedFlow<String>? = null) =
async(Dispatchers.IO) {
val selection = getFileTypeSelection(fileSuffix)
val fileList: MutableList<File> = ArrayList()
val projection = arrayOf(
MediaStore.Files.FileColumns._ID, MediaStore.Files.FileColumns.DATA,
)
val sortOrder = MediaStore.Files.FileColumns._ID + " DESC"
val queryUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
} else {
MediaStore.Files.getContentUri("external")
}
val cursor = context.contentResolver.query(queryUri, projection, selection, null, sortOrder)
if (cursor != null) {
while (cursor.moveToNext()) {
delay(150)
val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA))
flow?.emit(path)
fileList.add(File(path))
}
cursor.close()
}
fileList
}
} }
\ 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:drawable="@drawable/bg_0571ed_25" android:state_enabled="true" />
<item android:drawable="@drawable/bg_f3f4f6_25" android:state_enabled="false" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F3F4F6" />
<corners android:radius="25dp" />
</shape>
\ No newline at end of file
...@@ -82,8 +82,10 @@ ...@@ -82,8 +82,10 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="35dp" android:layout_height="35dp"
android:background="#1A000000" android:background="#1A000000"
android:ellipsize="middle"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingStart="15dp" android:paddingHorizontal="15dp"
android:singleLine="true"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="12sp" android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
...@@ -111,8 +113,16 @@ ...@@ -111,8 +113,16 @@
android:layout_width="338dp" android:layout_width="338dp"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_marginBottom="30dp" android:layout_marginBottom="30dp"
android:background="@drawable/bg_clean_btn"
android:enabled="false"
android:gravity="center"
android:text="Scan in progress"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#AEAEB0"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
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