Commit 5b93ee4e authored by wanglei's avatar wanglei

...ui

parent 152b3f4b
......@@ -76,6 +76,7 @@ dependencies {
//第三方UI
implementation("com.airbnb.android:lottie:6.4.0")
implementation("com.github.bumptech.glide:glide:4.16.0")
implementation("com.github.pokercc:ExpandableRecyclerView:0.9.3")
//网络
implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1'
......
......@@ -35,6 +35,24 @@
android:launchMode="singleTask"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".activity.junkclean.ScanJunkActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".activity.junkclean.CleanJunkActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".activity.junkclean.CleaningActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".activity.privacyspace.PrivacyManageActivity"
android:exported="false"
......@@ -52,7 +70,9 @@
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" /> <!-- <activity -->
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<!-- <activity -->
<!-- android:name=".activity.whatsapp.WhatsAppCleanerActivity" -->
<!-- android:exported="false" -->
<!-- android:launchMode="singleTop" -->
......@@ -90,25 +110,25 @@
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".activity.FileRecoveredActivity"
android:name=".activity.recovery.FileRecoveredActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".activity.FileScanResultActivity"
android:name=".activity.recovery.FileScanResultActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".activity.FileRecoveryActivity"
android:name=".activity.recovery.FileRecoveryActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".activity.FileScanActivity"
android:name=".activity.recovery.FileScanActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
......
{"v":"5.9.2","fr":30,"ip":0,"op":60,"w":1020,"h":1020,"nm":"合成 1","ddd":0,"assets":[{"id":"image_0","w":270,"h":270,"u":"images/","p":"img_0.png","e":0},{"id":"image_1","w":729,"h":729,"u":"images/","p":"img_1.png","e":0},{"id":"comp_0","nm":"外圆","fr":30,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"形状图层 6","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[10],"e":[0]},{"t":40}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[510,510,0],"ix":2,"l":2},"a":{"a":0,"k":[-23.227,28.773,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100],"e":[140,140,100]},{"t":40}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[729,729],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.16470600203,0.431372997808,0.96470600203,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-23.227,28.773],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":40,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"形状图层 7","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":20,"s":[10],"e":[0]},{"t":60}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[510,510,0],"ix":2,"l":2},"a":{"a":0,"k":[-23.227,28.773,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":20,"s":[100,100,100],"e":[140,140,100]},{"t":60}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[729,729],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.16470600203,0.431372997808,0.96470600203,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-23.227,28.773],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":20,"op":60,"st":20,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"形状图层 8","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[10],"e":[0]},{"t":80}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[510,510,0],"ix":2,"l":2},"a":{"a":0,"k":[-23.227,28.773,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":40,"s":[100,100,100],"e":[140,140,100]},{"t":80}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[729,729],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.16470600203,0.431372997808,0.96470600203,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-23.227,28.773],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":40,"op":80,"st":40,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"Group 153.png","cl":"png","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[510,510,0],"ix":2,"l":2},"a":{"a":0,"k":[135,135,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"Group 159.png","cl":"png","refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0],"e":[360]},{"t":60}],"ix":10},"p":{"a":0,"k":[510,510,0],"ix":2,"l":2},"a":{"a":0,"k":[364.5,364.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"外圆","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[510,510,0],"ix":2,"l":2},"a":{"a":0,"k":[510,510,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1020,"h":1020,"ip":0,"op":20,"st":-20,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"外圆","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[510,510,0],"ix":2,"l":2},"a":{"a":0,"k":[510,510,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1020,"h":1020,"ip":20,"op":40,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"外圆","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[510,510,0],"ix":2,"l":2},"a":{"a":0,"k":[510,510,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1020,"h":1020,"ip":40,"op":60,"st":20,"bm":0}],"markers":[]}
\ No newline at end of file
package com.base.datarecovery.activity
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import androidx.activity.OnBackPressedCallback
import androidx.core.view.updatePadding
import com.base.datarecovery.activity.junkclean.ScanJunkActivity
import com.base.datarecovery.adapter.AppFunctionAdapter
import com.base.datarecovery.ads.AdmobInterstitialUtils
import com.base.datarecovery.ads.AdmobNativeUtils
import com.base.datarecovery.bean.ConstObject.JUNK_CLEANER
import com.base.datarecovery.bean.ConstObject.REPEAT_PHOTOS
import com.base.datarecovery.bean.ConstObject.SCREENSHOT_CLEANER
import com.base.datarecovery.databinding.ActivityLayoutResultBinding
import com.base.datarecovery.help.BaseActivity
import com.base.datarecovery.help.KotlinExt.toFormatSize
import com.base.datarecovery.utils.BarUtils
import com.base.datarecovery.utils.SPUtils
class ResultActivity : BaseActivity<ActivityLayoutResultBinding>() {
override val binding: ActivityLayoutResultBinding by lazy {
ActivityLayoutResultBinding.inflate(layoutInflater)
}
private lateinit var adapter: AppFunctionAdapter
@SuppressLint("SetTextI18n", "NotifyDataSetChanged")
override fun initView() {
BarUtils.setStatusBarColor(this, Color.TRANSPARENT)
binding.clTop.updatePadding(top = BarUtils.getStatusBarHeight())
adapter = AppFunctionAdapter {
when (it) {
JUNK_CLEANER -> {
startActivity(Intent(this, ScanJunkActivity::class.java))
}
REPEAT_PHOTOS -> {
startActivity(Intent(this, RepeatActivity::class.java))
}
SCREENSHOT_CLEANER -> {
startActivity(Intent(this, ScreenShotActivity::class.java))
}
}
finish()
}
binding.rvFun.adapter = adapter
adapter.updateListPosition()
adapter.notifyDataSetChanged()
val from = intent.getStringExtra("from")
when (from) {
JUNK_CLEANER -> {
if (intent.getLongExtra("clean_size", 0L) > 0) {
val size = intent.getLongExtra("clean_size", 0L).toFormatSize(1)
binding.tvInfo.text = "Cleaned up $size"
} else {
binding.tvInfo.text = "No junk files found."
}
SPUtils.getInstance().put("last_use_junk_cleaner", System.currentTimeMillis())
}
else -> {}
}
from?.let {
binding.tvTitle.text = it
adapter.removeItem(it)
}
onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
AdmobInterstitialUtils.showInterstitialAd(this@ResultActivity) {
finishToMain()
}
}
})
binding.ivBack.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
AdmobNativeUtils.showNativeAd(this@ResultActivity, binding.flAd)
}
override fun onDestroy() {
super.onDestroy()
binding.icSuccess.clearAnimation()
}
}
\ No newline at end of file
package com.base.datarecovery.activity.junkclean
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import androidx.activity.OnBackPressedCallback
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.recyclerview.widget.LinearLayoutManager
import com.base.datarecovery.R
import com.base.datarecovery.activity.ResultActivity
import com.base.datarecovery.ads.AdmobInterstitialUtils
import com.base.datarecovery.ads.AdmobNativeUtils
import com.base.datarecovery.bean.ChildBean
import com.base.datarecovery.bean.ConstObject.JUNK_CLEANER
import com.base.datarecovery.bean.ParentBean
import com.base.datarecovery.databinding.ActivityLayoutCleanJunkBinding
import com.base.datarecovery.databinding.ItemChildBinding
import com.base.datarecovery.databinding.ItemParentBinding
import com.base.datarecovery.help.BaseActivity
import com.base.datarecovery.help.KotlinExt.toFormatSize
import com.base.datarecovery.utils.BarUtils
import com.base.datarecovery.utils.MediaStoreUtils
import pokercc.android.expandablerecyclerview.ExpandableAdapter
/**
* 清理数据获取页面
*/
class CleanJunkActivity : BaseActivity<ActivityLayoutCleanJunkBinding>() {
private val parentList by lazy {
mutableListOf(
ParentBean(
title = "Useless installation package",
childItem = child3,
parentSize = sizes[0],
isParentSelected = true,
expanded = false
),
ParentBean(
title = "Residual cache junk",
childItem = child4,
parentSize = sizes[1],
isParentSelected = true,
expanded = false
),
ParentBean(
title = "Clean up more",
childItem = child5,
parentSize = sizes[2],
isParentSelected = true,
expanded = false
)
)
}
private val child1 = ArrayList<ChildBean>()
private val child2 = ArrayList<ChildBean>()
private val child3 = ArrayList<ChildBean>()
private val child4 = ArrayList<ChildBean>()
private val child5 = ArrayList<ChildBean>()
private val sizes = MutableList(3) { 0L }
private var scanCount = 0
private val selectList = mutableListOf<String>()
private var selectSize = 0L
override val binding: ActivityLayoutCleanJunkBinding by lazy {
ActivityLayoutCleanJunkBinding.inflate(layoutInflater)
}
override fun initView() {
BarUtils.setStatusBarColor(this, Color.TRANSPARENT)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
AdmobNativeUtils.showNativeAd(this@CleanJunkActivity, binding.flAd)
setAdapter()
}
override fun initListener() {
binding.idJunksBack.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
AdmobInterstitialUtils.showInterstitialAd(this@CleanJunkActivity) {
finishToMain()
}
}
})
binding.idClBtn.setOnClickListener {
if (binding.idClBtn.text == "Got it") {
startActivity(Intent(this@CleanJunkActivity, ResultActivity::class.java).apply {
putExtra("clean_size", JUNK_CLEANER)
putExtra("from", 0)
})
} else {
startActivity(
Intent(this, CleaningActivity::class.java)
.putExtra("list", selectList.toTypedArray())
.putExtra("size", selectSize)
)
}
finish()
}
}
private fun setAdapter() {
binding.idExRl.adapter = mAdapter
binding.idExRl.layoutManager = LinearLayoutManager(this)
scanJunk()
}
private fun scanJunk() {
val apk = MediaStoreUtils.queryFiles(this, MediaStoreUtils.FileType.APK) ?: listOf()
apk.forEach { l ->
sizes[0] += l.size
val bean = ChildBean(R.mipmap.apk, l.name, l.path, l.size)
child3.add(bean)
}
scanCount += 1
updateSize(doneIndex = 0)
val temp = MediaStoreUtils.queryFiles(this, MediaStoreUtils.FileType.TMP) ?: listOf()
temp.forEach { l ->
sizes[1] += l.size
val bean = ChildBean(null, l.name, l.path, l.size)
child4.add(bean)
}
scanCount += 1
updateSize(doneIndex = 1)
val log = MediaStoreUtils.queryFiles(this, MediaStoreUtils.FileType.LOG) ?: listOf()
log.forEach { l ->
sizes[2] += l.size
val bean = ChildBean(null, l.name, l.path, l.size)
child5.add(bean)
}
scanCount += 2
updateSize(doneIndex = 2)
}
@SuppressLint("SetTextI18n")
private fun updateSize(doneIndex: Int = -1) {
addData(index = doneIndex)
val split = sizes.sum().toFormatSize(1).split(' ')
binding.idKeCl.text = split[0]
binding.idSizeUnit.text = split[1]
if (scanCount >= 3) {
selectList.clear()
selectSize = 0L
for (i in parentList.indices) {
if (parentList[i].childItem.isNotEmpty()) {
val childSize = parentList[i].childItem.filter {
it.isChildSelected
}.sumOf {
it.childSize
}
for (a in parentList[i].childItem) {
if (a.isChildSelected) {
if (a.pathList?.isNotEmpty() == true) {
for (o in a.pathList!!) {
selectList.add(o)
}
}
}
}
selectSize += childSize
} else {
if (parentList[i].isParentSelected) {
selectSize += parentList[i].parentSize
}
}
}
parentList.forEach { parent ->
selectList.addAll(parent.childItem.filter {
it.isChildSelected
}.map { it.chilepath })
}
}
binding.idClBtn.isVisible = scanCount >= 3
binding.idClBtn.isEnabled = sizes.sum() > 0
if (scanCount >= 3 && sizes.sum().toInt() == 0) {
// AdmobUtils.showInterstitialAd(this) {
// startActivity(
// Intent(this, ResultActivity::class.java).putExtra(
// "from",
// AFunOb.JUNK_CLEANER
// ).putExtra("clean_size", 0L)
// )
// finish()
// }
binding.idClBtn.text = "Got it"
} else {
binding.idClBtn.text = "Clean up ${selectSize.toFormatSize(1)}"
}
binding.idClBtn.isEnabled = true
}
@SuppressLint("NotifyDataSetChanged")
private fun addData(index: Int) {
if (parentList.isNotEmpty()) {
parentList[index].isfinish = true
parentList[index].parentSize = sizes[index]
mAdapter.notifyDataSetChanged()
}
}
@SuppressLint("SetTextI18n")
private fun updateView() {
selectList.clear()
var allSize = 0L
for (i in parentList.indices) {
if (parentList[i].childItem.isNotEmpty()) {
val childSize = parentList[i].childItem.filter {
it.isChildSelected
}.sumOf {
it.childSize
}
for (a in parentList[i].childItem) {
if (a.isChildSelected) {
if (a.pathList?.isNotEmpty() == true) {
for (o in a.pathList!!) {
selectList.add(o)
}
}
}
}
allSize += childSize
} else {
if (parentList[i].isParentSelected) {
allSize += parentList[i].parentSize
}
}
}
selectSize = allSize
binding.idClBtn.text = "Clean up ${allSize.toFormatSize()}"
binding.idClBtn.isEnabled = allSize > 0
parentList.forEach { parent ->
selectList.addAll(parent.childItem.filter {
it.isChildSelected
}.map { it.chilepath })
}
}
private val mAdapter by lazy {
class ParentViewHolder(val binding: ItemParentBinding) :
ExpandableAdapter.ViewHolder(binding.root)
class ChildViewHolder(val binding: ItemChildBinding) :
ExpandableAdapter.ViewHolder(binding.root)
object : ExpandableAdapter<ExpandableAdapter.ViewHolder>() {
var animators = mutableMapOf<Int, ValueAnimator>()
override fun getChildCount(groupPosition: Int): Int {
return parentList[groupPosition].childItem.size
}
override fun getGroupCount(): Int {
return parentList.size
}
override fun onViewDetachedFromWindow(holder: ViewHolder) {
super.onViewDetachedFromWindow(holder)
animators[holder.adapterPosition]?.pause()
}
override fun onViewAttachedToWindow(holder: ViewHolder) {
super.onViewAttachedToWindow(holder)
animators[holder.adapterPosition]?.resume()
}
override fun onCreateChildViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(viewGroup.context)
val binding = ItemChildBinding.inflate(inflater, viewGroup, false)
return ChildViewHolder(binding)
}
override fun onCreateGroupViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(viewGroup.context)
val binding = ItemParentBinding.inflate(inflater, viewGroup, false)
return ParentViewHolder(binding)
}
override fun onGroupViewHolderExpandChange(
holder: ViewHolder,
groupPosition: Int,
animDuration: Long,
expand: Boolean
) {
}
@SuppressLint("NotifyDataSetChanged")
override fun onBindGroupViewHolder(
holder: ViewHolder,
groupPosition: Int,
expand: Boolean,
payloads: List<Any>
) {
val viewHolder = holder as? ParentViewHolder ?: return
val parentType = parentList[groupPosition]
viewHolder.binding.idTypeName.text = parentType.title
parentType.expanded = expand
if (parentType.expanded) {
viewHolder.binding.idXiala.setImageResource(R.mipmap.shouqi)
} else {
viewHolder.binding.idXiala.setImageResource(R.mipmap.zhankai)
}
if (parentType.isfinish) {
viewHolder.binding.idImgLoad.isVisible = false
viewHolder.binding.idImgChoose.isVisible = true
} else {
val animator =
animators[groupPosition] ?: ValueAnimator.ofFloat(0f, 360f).apply {
duration = 1000
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
interpolator = LinearInterpolator()
addUpdateListener {
holder.binding.idImgLoad.rotation = it.animatedValue as Float
}
start()
animators[groupPosition] = this
}
viewHolder.binding.idImgLoad.isVisible = true
viewHolder.binding.idImgChoose.isVisible = false
}
viewHolder.binding.idTypeSize.text = parentType.parentSize.toFormatSize(1)
viewHolder.binding.idXiala.isVisible = parentType.childItem.isNotEmpty()
viewHolder.binding.idImgChoose.isSelected = parentType.isParentSelected
viewHolder.binding.idImgChoose.setOnClickListener {
viewHolder.binding.idImgChoose.isSelected =
!viewHolder.binding.idImgChoose.isSelected
parentType.isParentSelected = !parentType.isParentSelected
if (parentType.isParentSelected) {
for (app in parentType.childItem) {
app.isChildSelected = true
notifyDataSetChanged()
}
} else {
for (app in parentType.childItem) {
app.isChildSelected = false
notifyDataSetChanged()
}
}
updateView()
}
}
@SuppressLint("NotifyDataSetChanged")
override fun onBindChildViewHolder(
holder: ViewHolder,
groupPosition: Int,
childPosition: Int,
payloads: List<Any>
) {
val viewHolder = holder as? ChildViewHolder ?: return
val childType = parentList[groupPosition].childItem[childPosition]
when (groupPosition) {
0 -> {
val packageManager: PackageManager = this@CleanJunkActivity.packageManager
val apkFilePath = childType.chilepath // 替换成您的APK文件路径
val packageInfo =
packageManager.getPackageArchiveInfo(
apkFilePath,
PackageManager.GET_ACTIVITIES
)
if (packageInfo != null) {
val applicationInfo = packageInfo.applicationInfo
val appIcon = packageManager.getApplicationIcon(applicationInfo)
viewHolder.binding.idImgIcon.setImageDrawable(appIcon)
}
}
1 -> {
viewHolder.binding.idImgIcon.setImageResource(R.mipmap.qingchuicon)
}
2 -> {
viewHolder.binding.idImgIcon.setImageResource(R.mipmap.del)
}
3 -> {
}
4 -> {
}
}
viewHolder.binding.idTvAppName.text = childType.childname
viewHolder.binding.idImgSelect.isSelected = childType.isChildSelected
viewHolder.binding.idTvSize.text = childType.childSize.toFormatSize()
viewHolder.itemView.setOnClickListener {
when (childPosition) {
childPosition -> {
viewHolder.binding.idImgSelect.isSelected =
!viewHolder.binding.idImgSelect.isSelected
childType.isChildSelected = !childType.isChildSelected
if (!childType.isChildSelected) {
parentList[groupPosition].isParentSelected = false
notifyDataSetChanged()
}
updateView()
}
}
}
}
}
}
override fun onDestroy() {
super.onDestroy()
for (animator in mAdapter.animators.values) {
animator.cancel()
}
}
}
\ No newline at end of file
package com.base.datarecovery.activity.junkclean
import android.animation.ValueAnimator
import android.graphics.Color
import android.view.animation.LinearInterpolator
import androidx.core.animation.doOnEnd
import androidx.core.view.updatePadding
import com.base.datarecovery.ads.AdmobInterstitialUtils
import com.base.datarecovery.databinding.ActivityLayoutCleanupingBinding
import com.base.datarecovery.help.BaseActivity
import com.base.datarecovery.utils.BarUtils
import com.base.datarecovery.utils.MediaStoreUtils
import com.base.datarecovery.utils.NewFileUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlin.random.Random
/**
* 实际清理页面
*/
class CleaningActivity : BaseActivity<ActivityLayoutCleanupingBinding>() {
override val binding: ActivityLayoutCleanupingBinding by lazy {
ActivityLayoutCleanupingBinding.inflate(layoutInflater)
}
private val intentSize by lazy {
intent.getLongExtra("size", -1)
}
private val listPath by lazy {
intent.getStringArrayExtra("list") ?: arrayOf()
}
override fun initView() {
BarUtils.setStatusBarColor(this, Color.TRANSPARENT)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
MainScope().launch(Dispatchers.IO) {
try {
listPath.forEach { NewFileUtils.delete(it) }
MediaStoreUtils.updateMediaStore(this@CleaningActivity, listPath)
} catch (_: Exception) {
} finally {
}
}
playAnm()
}
private fun playAnm() {
ValueAnimator.ofFloat(0f, 360f).run {
duration = 1000
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
interpolator = LinearInterpolator()
addUpdateListener {
binding.idYuan.rotation = it.animatedValue as Float
}
start()
}
ValueAnimator.ofInt(0, 100).run {
duration = Random.nextLong(7000, 8000)
interpolator = LinearInterpolator()
addUpdateListener {
binding.idTvJd.text = "${it.animatedValue as Int}"
}
doOnEnd {
AdmobInterstitialUtils.showInterstitialAd(this@CleaningActivity) {
// startActivity(
// Intent(this@CleaningActivity, ResultActivity::class.java).putExtra("from", AFunOb.JUNK_CLEANER)
// .putExtra("clean_size", intentSize)
// )
// finish()
}
}
start()
}
}
}
\ No newline at end of file
package com.base.datarecovery.activity.junkclean
import android.animation.ValueAnimator
import android.content.Intent
import android.graphics.Color
import android.widget.Toast
import androidx.activity.addCallback
import androidx.core.view.updatePadding
import com.base.datarecovery.ads.AdmobInterstitialUtils
import com.base.datarecovery.ads.AdmobNativeUtils
import com.base.datarecovery.databinding.ActivityLayoutScanJunkBinding
import com.base.datarecovery.help.BaseActivity
import com.base.datarecovery.help.PermissionHelp.checkStorePermission
import com.base.datarecovery.help.PermissionHelp.requestStorePermission
import com.base.datarecovery.utils.BarUtils
import com.base.datarecovery.view.DialogViews.showGerPermission
/**
* 清理动画页面
*/
class ScanJunkActivity : BaseActivity<ActivityLayoutScanJunkBinding>() {
override val binding: ActivityLayoutScanJunkBinding by lazy {
ActivityLayoutScanJunkBinding.inflate(layoutInflater)
}
override fun initView() {
BarUtils.setStatusBarColor(this, Color.TRANSPARENT)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
AdmobNativeUtils.showNativeAd(this, binding.flAd)
if (checkStorePermission()) {
playLottie()
} else {
showGerPermission(tittle = "Storage Permission Required",
desc = "This feature requires access to your storage to scan your files and clean up junk files and unused APK files. We will not transmit your data to any third-party service. Please grant permission so that we can provide you with better service.",
deny = { finishToMain() },
allow = {
requestStorePermission(launcher, result = {
if (it) playLottie() else finishToMain()
})
})
}
}
override fun initListener() {
onBackPressedDispatcher.addCallback {
Toast.makeText(this@ScanJunkActivity, "wait a moment", Toast.LENGTH_SHORT).show()
}
}
private var isPause = false
override fun onResume() {
super.onResume()
if (isPause) {
binding.idJunkScan.resumeAnimation()
}
isPause = false
}
override fun onDestroy() {
super.onDestroy()
animator1?.cancel()
animator2?.cancel()
animator3?.cancel()
binding.idJunkScan.cancelAnimation()
}
override fun onPause() {
super.onPause()
isPause = true
animator1?.pause()
animator2?.pause()
animator3?.pause()
binding.idJunkScan.pauseAnimation()
}
private fun playLottie() {
binding.idJunkScan.imageAssetsFolder = "junk_scan/images/"
binding.idJunkScan.setAnimation("junk_scan/data.json")
binding.idJunkScan.playAnimation()
binding.root.postDelayed({
AdmobInterstitialUtils.showInterstitialAd(this) {
startActivity(Intent(this, CleanJunkActivity::class.java))
finish()
}
}, 5000)
}
private var animator1: ValueAnimator? = null
private var animator2: ValueAnimator? = null
private var animator3: ValueAnimator? = null
}
\ No newline at end of file
package com.base.datarecovery.activity
package com.base.datarecovery.activity.recovery
import android.graphics.Color
import android.os.Bundle
......
package com.base.datarecovery.activity
package com.base.datarecovery.activity.recovery
import android.annotation.SuppressLint
import android.content.Intent
......
package com.base.datarecovery.activity
package com.base.datarecovery.activity.recovery
import android.annotation.SuppressLint
import android.content.Intent
......@@ -7,6 +7,8 @@ import android.os.Environment
import android.view.View
import androidx.lifecycle.lifecycleScope
import com.base.datarecovery.R
import com.base.datarecovery.ads.AdmobNativeUtils
import com.base.datarecovery.ads.AdmobOpenUtils
import com.base.datarecovery.bean.ConstObject
import com.base.datarecovery.databinding.ActivityFileScanBinding
import com.base.datarecovery.help.BaseActivity
......@@ -61,6 +63,7 @@ class FileScanActivity : BaseActivity<ActivityFileScanBinding>() {
binding.ivIcon.setImageResource(R.mipmap.tu_videos_scan)
}
}
AdmobNativeUtils.showNativeAd(this, binding.flAd)
}
override fun initListener() {
......@@ -122,7 +125,10 @@ class FileScanActivity : BaseActivity<ActivityFileScanBinding>() {
private fun requestPermission() {
showGerPermission(null, deny = { }, allow = {
showGerPermission(tittle = "Storage Permission Required",
desc = "This feature requires access to your storage to scan your photos, videos, and documents and recover any accidentally deleted data. We will not transmit your data to any third-party service. Please grant permission so that we can provide you with better service.",
deny = { },
allow = {
requestStorePermission(launcher, jumpAction = {}, result = { flag ->
if (flag) beginScan()
......
package com.base.datarecovery.activity
package com.base.datarecovery.activity.recovery
import android.annotation.SuppressLint
import android.content.Intent
......
package com.base.datarecovery.adapter
import android.annotation.SuppressLint
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.base.datarecovery.R
import com.base.datarecovery.bean.ConstObject.JUNK_CLEANER
import com.base.datarecovery.bean.ConstObject.REPEAT_PHOTOS
import com.base.datarecovery.bean.ConstObject.SCREENSHOT_CLEANER
import com.base.datarecovery.databinding.ItemResultFunBinding
import com.base.datarecovery.utils.SPUtils
import com.base.datarecovery.view.XmlEx.inflate
import java.util.Collections
class AppFunctionAdapter(val click: (name: String) -> Unit) :
RecyclerView.Adapter<AppFunctionAdapter.JJJ>() {
val list = arrayListOf(
Fun(JUNK_CLEANER, R.mipmap.h_cleanjunk, "Clean junk regularly to free up space", "Clean Up"),
Fun(REPEAT_PHOTOS, R.mipmap.h_similar, "Check similar photos to release more space", "Clean Up"),
Fun(SCREENSHOT_CLEANER, R.mipmap.h_screenshot, "Too many screenshots? Free up your phone storage!", "Clean Up"),
)
class JJJ(view: View) : ViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JJJ {
return JJJ(R.layout.item_result_fun.inflate(parent))
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: JJJ, position: Int) {
val data = list[position]
val context = holder.itemView.context
val binding = ItemResultFunBinding.bind(holder.itemView)
binding.ivIcon.setImageDrawable(ContextCompat.getDrawable(context, data.icon))
binding.tvTittle.text = data.name
binding.tvDes.text = data.des
binding.tvButton.text = data.button
binding.tvButton.setOnClickListener {
click.invoke(data.name)
}
}
@SuppressLint("NotifyDataSetChanged")
fun removeItem(name: String) {
list.removeIf { it.name == name }
notifyDataSetChanged()
}
data class Fun(
val name: String = "",
val icon: Int = 0,
val des: String = "",
val button: String = "",
)
fun updateListPosition() {
//本次进入结果页,判断使用垃圾的功能是否超过5分钟
val lastUseJunkCleaner = SPUtils.getInstance().getLong("last_use_junk_cleaner", 0)
if ((System.currentTimeMillis() - lastUseJunkCleaner) >= 60 * 5 * 1000) {
} else {
Collections.rotate(list, list.size - 1)
}
}
}
\ No newline at end of file
......@@ -95,10 +95,10 @@ object AdmobNativeUtils {
}
if (nativeAd == null) {
loadNativeAd()
val obj = JSONObject()
obj.put("reason", "no_ad")
obj.put("ad_unit", "nativeAd")
// EventUtils.event("ad_show_error", ext = obj)
val obj2 = JSONObject()
obj2.put("reason", "no_ad")
obj2.put("ad_unit", "nativeAd")
// EventUtils.event("ad_show_error", ext = obj2)
} else {
loadingListener?.invoke()
}
......
......@@ -28,7 +28,7 @@ class NativeView @JvmOverloads constructor(
nativeAd ?: return
val adView = LayoutInflater.from(context)
.inflate(R.layout.layout_native, this, false) as NativeAdView
.inflate(R.layout.layout_native_small, this, false) as NativeAdView
adView.mediaView = adView.findViewById(R.id.ad_media)
adView.headlineView = adView.findViewById(R.id.ad_headline)
......
......@@ -4,6 +4,11 @@ import com.base.datarecovery.utils.SPUtils
object ConstObject {
const val JUNK_CLEANER = "Junk Cleaner"
const val REPEAT_PHOTOS = "Repeat Photos"
const val PHOTO_COMPRESS = "Photo Compress"
const val SCREENSHOT_CLEANER = "Screenshot Cleaner"
const val SCAN_PHOTOS = 1
const val SCAN_DOCUMENTS = 2
const val SCAN_VIDEOS = 3
......
package com.base.datarecovery.bean
data class FileBean(
var name: String = "",
var path: String,
val size: Long,
val isDir: Boolean = false,
val type: String = "",
val time: Long = 0L,
var isSelect: Boolean = false
) {
fun isImage() = !isDir && type in listOf("png", "jpg", "gif")
fun isVideo() = !isDir && type in listOf("mp4")
fun isAudio() = !isDir && type in listOf("mp3")
fun isLargeFile() = !isDir && size >= 10 * 1024 * 1024
fun isZip() = !isDir && type in listOf("zip", "tar", "7z")
fun isApk() = !isDir && type in listOf("apk")
fun isDoc() = !isDir && type in listOf("pdf", "doc", "docx", "xls", "ppt", "txt")
fun isOther() = !isImage() && !isVideo() && !isAudio() && !isZip() && !isApk()
fun isJunk() = !isDir && type in listOf("tmp", "cache", "temp")
// fun isOtherTrash() = !isDir && type in listOf("log", "bak", "old", "chk", "gid", "dmp", "thumb", "crdownload", "part", "trash", "trashes")
fun isOtherTrash() = !isDir && type in listOf("log","tmp")
override fun toString(): String {
return "FileBean(name='$name', path='$path', size=$size, isDir=$isDir, type='$type', time=$time, isSelect=$isSelect)"
}
}
\ No newline at end of file
package com.base.datarecovery.bean
data class ParentBean(
val title: String,
val childItem: List<ChildBean>,
var parentSize: Long,
var isParentSelected: Boolean,
var expanded: Boolean = true,
var isfinish: Boolean = false
)
data class ChildBean(
val image: Int? = null,
val childname: String,
val chilepath: String="",
val childSize: Long = 0L,
var isChildSelected: Boolean = true,
var pathList: List<String>? = null,
var packageName:String?=""
)
\ No newline at end of file
......@@ -6,9 +6,10 @@ import android.annotation.SuppressLint
import android.content.Intent
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import com.base.datarecovery.activity.FileScanActivity
import com.base.datarecovery.activity.recovery.FileScanActivity
import com.base.datarecovery.activity.RepeatActivity
import com.base.datarecovery.activity.ScreenShotActivity
import com.base.datarecovery.activity.junkclean.ScanJunkActivity
import com.base.datarecovery.activity.privacyspace.PrivacyPinOneActivity
import com.base.datarecovery.activity.privacyspace.PrivacySpaceActivity
import com.base.datarecovery.ads.AdmobNativeUtils
......@@ -32,7 +33,9 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
}
override fun setListener() {
binding.flScan.setOnClickListener {
startActivity(Intent(requireContext(), ScanJunkActivity::class.java))
}
binding.flRyPhoto.setOnClickListener {
startActivity(Intent(requireContext(), FileScanActivity::class.java).apply {
putExtra("Type", SCAN_PHOTOS)
......
package com.base.datarecovery.utils;
import android.content.Context;
import android.database.Cursor;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.text.TextUtils;
import com.base.datarecovery.bean.FileBean;
import java.util.ArrayList;
import java.util.List;
public class MediaStoreUtils {
public enum FileType {
APK(".apk"), LOG(".log"), TMP(".tmp"), IMAGE(".jpg");
private String suffix;
FileType(String suffix) {
this.suffix = suffix;
}
public String getSuffix() {
return suffix;
}
}
public static List<FileBean> queryFiles(Context context, FileType fileType) {
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_NONE + " AND "
+ MediaStore.Files.FileColumns.DATA + " LIKE '%" + fileType.getSuffix() + "'";
return queryFiles(context, selection);
}
private static List<FileBean> queryFiles(Context context, String selection) {
List<FileBean> fileList = new ArrayList<>();
String[] projection = {MediaStore.Files.FileColumns._ID, MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.SIZE, MediaStore.Files.FileColumns.DISPLAY_NAME, MediaStore.Files.FileColumns.DATE_ADDED};
String sortOrder = MediaStore.Files.FileColumns._ID + " DESC";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Uri queryUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
Cursor cursor = context.getContentResolver().query(queryUri, projection, selection, null, sortOrder);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME));
String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA));
long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.SIZE));
long createTime = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATE_ADDED)); // 获取文件创建时间
if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(path)) {
fileList.add(new FileBean(name, path, size, false, getFileExtension(name), createTime, false));
}
}
cursor.close();
}
} else {
Uri queryUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
Cursor cursor = context.getContentResolver().query(queryUri, projection, selection, null, sortOrder);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME));
String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA));
long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.SIZE));
long createTime = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATE_ADDED)); // 获取文件创建时间
if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(path)) {
fileList.add(new FileBean(name, path, size, false, getFileExtension(name), createTime, false));
}
}
cursor.close();
}
}
return fileList;
}
public static List<FileBean> queryLargeFiles(Context context, long minSize) {
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_NONE + " AND "
+ MediaStore.Files.FileColumns.SIZE + ">=" + minSize;
return queryFiles(context, selection);
}
private static String getFileExtension(String fileName) {
String extension = "unknown";
if (TextUtils.isEmpty(fileName)) {
return extension;
}
int i = fileName.lastIndexOf('.');
if (i > 0 && i < fileName.length() - 1) {
int s = i + 1;
if (s < fileName.length()) {
extension = fileName.substring(i + 1);
}
}
return extension;
}
public static void updateMediaStore(Context context, String[] filePath) {
MediaScannerConnection.scanFile(
context,
filePath,
null,
(path, uri) -> {
// 扫描结束后的回调
// 可以在这里处理更新MediaStore后的操作
}
);
}
}
package com.base.datarecovery.utils
import android.util.Log
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileFilter
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.util.Collections
object NewFileUtils {
fun delete(filePath: String?): Boolean {
return delete(getFileByPath(filePath))
}
private fun delete(file: File?): Boolean {
if (file == null) return false
if (file.isDirectory) {
return deleteDir(file)
}
return deleteFile(file)
}
fun getFileByPath(filePath: String?): File? {
return if (isSpace(filePath)) null else File(filePath)
}
private fun isSpace(s: String?): Boolean {
if (s == null) return true
var i = 0
val len = s.length
while (i < len) {
if (!Character.isWhitespace(s[i])) {
return false
}
++i
}
return true
}
private fun deleteDir(dir: File?): Boolean {
if (dir == null) return false
// dir doesn't exist then return true
if (!dir.exists()) return true
// dir isn't a directory then return false
if (!dir.isDirectory) return false
val files = dir.listFiles()
if (files != null && files.size > 0) {
for (file in files) {
if (file.isFile) {
if (!file.delete()) return false
} else if (file.isDirectory) {
if (!deleteDir(file)) return false
}
}
}
return dir.delete()
}
private fun deleteFile(file: File?): Boolean {
return file != null && (!file.exists() || file.isFile && file.delete())
}
fun listFilesInDir(dirPath: String?): List<File> {
return listFilesInDir(dirPath, null)
}
private fun listFilesInDir(dirPath: String?, comparator: Comparator<File?>?): List<File> {
return listFilesInDir(getFileByPath(dirPath), false, comparator)
}
private fun listFilesInDir(dir: File?, isRecursive: Boolean, comparator: java.util.Comparator<File?>?): List<File> {
return listFilesInDirWithFilter(dir, { true }, isRecursive, comparator)
}
private fun listFilesInDirWithFilterInner(dir: File?, filter: FileFilter?, isRecursive: Boolean): List<File> {
val list: MutableList<File> = ArrayList()
if (!isDir(dir)) return list
val files = dir?.listFiles()
if (files != null && files.size > 0) {
for (file in files) {
if (filter?.accept(file) == true) {
list.add(file)
}
if (isRecursive && file.isDirectory) {
list.addAll(listFilesInDirWithFilterInner(file, filter, true))
}
}
}
return list
}
private fun isDir(dirPath: String?): Boolean {
return isDir(getFileByPath(dirPath))
}
/**
* Return whether it is a directory.
*
* @param file The file.
* @return `true`: yes<br></br>`false`: no
*/
private fun isDir(file: File?): Boolean {
return file != null && file.exists() && file.isDirectory
}
private fun listFilesInDirWithFilter(dir: File?, filter: FileFilter?, isRecursive: Boolean, comparator: java.util.Comparator<File?>?): List<File> {
val files = listFilesInDirWithFilterInner(dir, filter, isRecursive)
if (comparator != null) {
Collections.sort(files, comparator)
}
return files
}
fun getFileExtension(file: File?): String {
if (file == null) return ""
return getFileExtension(file.path)
}
fun getFileExtension(filePath: String): String {
if (isSpace(filePath)) return ""
val lastPoi = filePath.lastIndexOf('.')
val lastSep = filePath.lastIndexOf(File.separator)
if (lastPoi == -1 || lastSep >= lastPoi) return ""
return filePath.substring(lastPoi + 1)
}
fun copy(srcPath: String?, destPath: String?): Boolean {
return copy(getFileByPath(srcPath), getFileByPath(destPath), null)
}
private fun copy(src: File?,
dest: File?,
listener: OnReplaceListener?): Boolean {
if (src == null) return false
if (src.isDirectory) {
return copyDir(src, dest, listener)
}
return copyFile(src, dest, listener)
}
private fun copyDir(srcDir: File,
destDir: File?,
listener: OnReplaceListener?): Boolean {
return copyOrMoveDir(srcDir, destDir, listener, false)
}
private fun copyFile(srcFile: File,
destFile: File?,
listener: OnReplaceListener?): Boolean {
return copyOrMoveFile(srcFile, destFile, listener, false)
}
fun move(srcPath: String?,
destPath: String?): Boolean {
return move(getFileByPath(srcPath), getFileByPath(destPath), null)
}
private fun move(src: File?,
dest: File?,
listener: OnReplaceListener?): Boolean {
if (src == null) return false
if (src.isDirectory) {
return moveDir(src, dest, listener)
}
return moveFile(src, dest, listener)
}
private fun moveDir(srcDir: File?,
destDir: File?,
listener: OnReplaceListener?): Boolean {
return copyOrMoveDir(srcDir, destDir, listener, true)
}
/**
* Move the file.
*
* @param srcFile The source file.
* @param destFile The destination file.
* @param listener The replace listener.
* @return `true`: success<br></br>`false`: fail
*/
private fun moveFile(srcFile: File?, destFile: File?, listener: OnReplaceListener?): Boolean {
return copyOrMoveFile(srcFile, destFile, listener, true)
}
private fun copyOrMoveDir(srcDir: File?,
destDir: File?,
listener: OnReplaceListener?,
isMove: Boolean): Boolean {
if (srcDir == null || destDir == null) return false
// destDir's path locate in srcDir's path then return false
val srcPath = srcDir.path + File.separator
val destPath = destDir.path + File.separator
if (destPath.contains(srcPath)) return false
if (!srcDir.exists() || !srcDir.isDirectory) return false
if (!createOrExistsDir(destDir)) return false
val files = srcDir.listFiles()
if (files != null && files.size > 0) {
for (file in files) {
val oneDestFile = File(destPath + file.name)
if (file.isFile) {
if (!copyOrMoveFile(file, oneDestFile, listener, isMove)) return false
} else if (file.isDirectory) {
if (!copyOrMoveDir(file, oneDestFile, listener, isMove)) return false
}
}
}
return !isMove || deleteDir(srcDir)
}
private fun copyOrMoveFile(srcFile: File?, destFile: File?, listener: OnReplaceListener?, isMove: Boolean): Boolean {
if (srcFile == null || destFile == null) return false
// srcFile equals destFile then return false
if (srcFile == destFile) return false
// srcFile doesn't exist or isn't a file then return false
if (!srcFile.exists() || !srcFile.isFile) return false
if (destFile.exists()) {
if (listener == null || listener.onReplace(srcFile, destFile)) { // require delete the old file
if (!destFile.delete()) { // unsuccessfully delete then return false
return false
}
} else {
return true
}
}
if (!createOrExistsDir(destFile.parentFile)) return false
try {
return (writeFileFromIS(destFile.absolutePath, FileInputStream(srcFile))
&& !(isMove && !deleteFile(srcFile)))
} catch (e: FileNotFoundException) {
e.printStackTrace()
return false
}
}
fun createOrExistsDir(dirPath: String?): Boolean {
return createOrExistsDir(getFileByPath(dirPath))
}
///////////////////////////////////////////////////////////////////////////
// writeFileFromIS without progress
///////////////////////////////////////////////////////////////////////////
private fun writeFileFromIS(filePath: String?, `is`: InputStream?): Boolean {
return writeFileFromIS(getFileByPath(filePath), `is`, false, null)
}
private fun writeFileFromIS(file: File?,
`is`: InputStream?,
append: Boolean,
listener: OnProgressUpdateListener?): Boolean {
if (`is` == null || !createOrExistsFile(file)) {
Log.e("FileIOUtils", "create file <$file> failed.")
return false
}
var os: OutputStream? = null
try {
os = BufferedOutputStream(FileOutputStream(file, append), sBufferSize)
if (listener == null) {
val data = ByteArray(sBufferSize)
var len: Int
while ((`is`.read(data).also { len = it }) != -1) {
os.write(data, 0, len)
}
} else {
val totalSize = `is`.available().toDouble()
var curSize = 0
listener.onProgressUpdate(0.0)
val data = ByteArray(sBufferSize)
var len: Int
while ((`is`.read(data).also { len = it }) != -1) {
os.write(data, 0, len)
curSize += len
listener.onProgressUpdate(curSize / totalSize)
}
}
return true
} catch (e: IOException) {
e.printStackTrace()
return false
} finally {
try {
`is`.close()
} catch (e: IOException) {
e.printStackTrace()
}
try {
os?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
fun rename(filePath: String?, newName: String?): Boolean {
return rename(getFileByPath(filePath), newName)
}
private fun rename(file: File?, newName: String?): Boolean {
// file is null then return false
if (file == null) return false
// file doesn't exist then return false
if (!file.exists()) return false
// the new name is space then return false
if (isSpace(newName)) return false
// the new name equals old name then return true
if (newName == file.name) return true
val newFile = File(file.parent + File.separator + newName)
// the new name of file exists then return false
return (!newFile.exists()
&& file.renameTo(newFile))
}
fun createOrExistsDir(file: File?): Boolean {
return file != null && (if (file.exists()) file.isDirectory else file.mkdirs())
}
private fun createOrExistsFile(file: File?): Boolean {
if (file == null) return false
if (file.exists()) return file.isFile
if (!createOrExistsDir(file.parentFile)) return false
try {
return file.createNewFile()
} catch (e: IOException) {
e.printStackTrace()
return false
}
}
private var sBufferSize = 524288
interface OnProgressUpdateListener {
fun onProgressUpdate(progress: Double)
}
interface OnReplaceListener {
fun onReplace(srcFile: File?, destFile: File?): Boolean
}
}
\ No newline at end of file
......@@ -45,6 +45,7 @@ object DialogViews {
@SuppressLint("SetTextI18n")
fun Context.showGerPermission(
tittle: String? = null,
desc: String? = null,
deny: ((view: Dialog) -> Unit)? = null,
allow: ((view: Dialog) -> Unit)? = null
): Dialog {
......@@ -58,7 +59,8 @@ object DialogViews {
dialog.setContentView(binding.root)
val str = resources.getString(R.string.app_name)
tittle?.let { binding.idTvTt.text = it }
tittle?.let { binding.tvTitle.text = it }
desc?.let { binding.tvDesc.text = it }
binding.idFullLottie.imageAssetsFolder = "recovery_permission_finger/images/"
binding.idFullLottie.setAnimation("recovery_permission_finger/data.json")
binding.idFullLottie.playAnimation()
......@@ -221,7 +223,7 @@ object DialogViews {
return dialog
}
fun Context.showDeletePermanentlyDialog( deleteAction: () -> Unit) {
fun Context.showDeletePermanentlyDialog(deleteAction: () -> Unit) {
val binding = DialogDeletePermanentlyBinding.inflate(LayoutInflater.from(this))
val dialog = AlertDialog.Builder(this, R.style.CustomAlertDialogStyle).create()
dialog.setView(binding.root)
......
package com.base.datarecovery.view
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import com.airbnb.lottie.LottieAnimationView
class XmlLottieAnimationView : LottieAnimationView {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun draw(canvas: Canvas) {
try {
super.draw(canvas)
} catch (e: Exception) {
}
}
override fun playAnimation() {
super.playAnimation()
}
}
\ 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="#1a4772ff" />
<corners android:radius="5dp" />
</shape>
\ No newline at end of file
......@@ -7,7 +7,7 @@
android:layout_height="match_parent"
android:background="#577DFD"
android:orientation="vertical"
tools:context=".activity.FileRecoveredActivity">
tools:context=".activity.recovery.FileRecoveredActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top"
......
......@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.FileRecoveryActivity">
tools:context=".activity.recovery.FileRecoveryActivity">
<androidx.constraintlayout.widget.ConstraintLayout
......
......@@ -5,7 +5,7 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.FileScanActivity">
tools:context=".activity.recovery.FileScanActivity">
<LinearLayout
android:id="@+id/ll_top"
......@@ -132,4 +132,10 @@
</LinearLayout>
<FrameLayout
android:id="@+id/fl_ad"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -7,7 +7,7 @@
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical"
tools:context=".activity.FileScanResultActivity">
tools:context=".activity.recovery.FileScanResultActivity">
<View
android:layout_width="match_parent"
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0164C8"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/id_top_rl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/id_junks_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="20dp"
android:src="@mipmap/fanhui" />
<TextView
android:id="@+id/id_tv_title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:text="Clean Junk"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</RelativeLayout>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:layout_marginBottom="10dp"
android:gravity="center_horizontal">
<TextView
android:id="@+id/id_ke_cl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginEnd="7dp"
android:includeFontPadding="false"
android:textColor="@color/white"
android:textSize="43sp"
android:textStyle="bold"
tools:text="0" />
<TextView
android:id="@+id/id_size_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="10dp"
android:includeFontPadding="false"
android:textColor="@color/white"
android:textSize="12sp"
tools:text="KB" />
</androidx.appcompat.widget.LinearLayoutCompat>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="43dp"
android:text="Cleanable"
android:textColor="#80FFFFFF"
android:textSize="14sp"
tools:ignore="HardcodedText" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/white">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/id_scan_reslut"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<pokercc.android.expandablerecyclerview.ExpandableRecyclerView
android:id="@+id/id_ex_rl"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="visible" />
<FrameLayout
android:id="@+id/fl_ad"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/id_cl_btn"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginHorizontal="40dp"
android:layout_marginVertical="20dp"
android:background="@drawable/bg_button_enable_selector"
android:enabled="false"
android:gravity="center"
android:text="Clean"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
android:visibility="gone"
tools:ignore="HardcodedText" />
</androidx.appcompat.widget.LinearLayoutCompat>
</FrameLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="169dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/id_bottomt_content"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/id_yuan"
android:layout_width="229dp"
android:layout_height="229dp"
android:layout_gravity="center_horizontal"
android:src="@mipmap/qingliz" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="124dp"
android:layout_height="124dp"
android:layout_gravity="center"
android:src="@mipmap/qingliyuan" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<TextView
android:id="@+id/id_tv_jd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="@color/white"
android:textSize="48sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="%"
android:textColor="@color/white"
android:textSize="14sp"
tools:ignore="HardcodedText" />
</androidx.appcompat.widget.LinearLayoutCompat>
</FrameLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/id_bottomt_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="150dp"
android:text="Wait a moment..."
android:textColor="#666666"
android:textSize="16sp"
tools:ignore="HardcodedText" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@color/theme_color"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:padding="10dp"
android:src="@mipmap/fanhui"
android:tint="@color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="19sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@id/iv_back"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_back"
tools:text="Junk Cleaner" />
<com.base.datarecovery.view.XmlLottieAnimationView
android:id="@+id/ic_success"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_marginTop="40dp"
android:scaleX="6"
android:scaleY="6"
app:layout_constraintBottom_toTopOf="@id/tv_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title"
app:lottie_autoPlay="true"
app:lottie_rawRes="@raw/new_complete" />
<TextView
android:id="@+id/tv_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ic_success"
tools:ignore="HardcodedText"
tools:text="Delete successful" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_fun"
android:layout_width="match_parent"
android:layout_height="0dp"
android:paddingTop="20dp"
android:paddingBottom="15dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toTopOf="@id/fl_ad"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cl_top"
app:layout_constraintVertical_bias="0.0" />
<FrameLayout
android:id="@+id/fl_ad"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/id_top_rl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/id_tv_title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:text="Clean Junk"
android:textColor="#333333"
android:textSize="18sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</RelativeLayout>
<com.base.datarecovery.view.XmlLottieAnimationView
android:id="@+id/id_junk_scan"
android:layout_width="300dp"
android:layout_height="300dp"
android:adjustViewBounds="true"
app:layout_constraintBottom_toTopOf="@id/tv"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_loop="true" />
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="295dp"
android:text="Wait a moment..."
android:textColor="#333333"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
<FrameLayout
android:id="@+id/fl_ad"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -12,6 +12,7 @@
android:layout_margin="20dp"
android:layout_weight="1"
android:orientation="horizontal"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
......
......@@ -15,6 +15,7 @@
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
......@@ -26,7 +27,7 @@
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/id_tv_tt"
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
......@@ -68,11 +69,11 @@
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_weight="1"
android:background="@drawable/bg_355bea_18"
android:gravity="center"
android:text="Allow"
android:textColor="@color/white"
android:textSize="17sp"
android:background="@drawable/bg_355bea_18"
tools:ignore="HardcodedText" />
</androidx.appcompat.widget.LinearLayoutCompat>
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="14dp"
android:layout_marginBottom="10dp"
android:gravity="center_vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/id_img_icon"
android:layout_width="40dp"
android:layout_height="40dp" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/id_tv_app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="1"
android:text="Ali Webpage ads"
android:textColor="#000000"
android:textSize="14sp"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/id_tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:text="Suggestion: Clean up"
android:textColor="#999999"
android:textSize="12sp"
tools:ignore="HardcodedText" />
</androidx.appcompat.widget.LinearLayoutCompat>
<TextView
android:id="@+id/id_tv_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3.3MB"
android:textColor="#999999"
android:textSize="13sp"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/id_img_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:background="@drawable/bg_square_selector"
tools:ignore="ContentDescription" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="14dp"
android:background="#EEEEEE" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="14dp"
android:layout_marginVertical="16dp"
android:gravity="center_vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/id_xiala"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="3dp"
android:src="@mipmap/shouqi" />
<TextView
android:id="@+id/id_type_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cache garbage"
android:textSize="14sp"
tools:ignore="HardcodedText" />
<View
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="@+id/id_type_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3.3MB"
android:textColor="#999999"
android:textSize="13sp"
tools:ignore="HardcodedText" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="14dp">
<ImageView
android:id="@+id/id_img_choose"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/bg_square_selector"
android:visibility="gone"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/id_img_load"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@mipmap/jiazai" />
</FrameLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:id="@+id/id_need_grant"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="14dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_1a4772ff_5"
android:gravity="center_vertical"
android:padding="12dp"
android:visibility="gone">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Grant permission to find more junk"
android:textColor="@color/theme_color"
android:textSize="13sp"
tools:ignore="HardcodedText" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/jianotu" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="11dp"
android:gravity="center_vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_icon"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="9dp"
android:src="@mipmap/h_cleanjunk" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_tittle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:text="Battery information"
android:textColor="#ff000000"
android:textSize="15sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_des"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:includeFontPadding="false"
android:text="View battery usage and details"
android:textColor="#666666"
android:textSize="13sp"
tools:ignore="HardcodedText" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
<TextView
android:id="@+id/tv_button"
android:layout_width="match_parent"
android:layout_height="34dp"
android:layout_marginHorizontal="54dp"
android:layout_marginTop="18dp"
android:layout_marginBottom="16dp"
android:background="@drawable/bg_355bea_10"
android:gravity="center"
android:text="Check Now"
android:textColor="#ffffffff"
android:textSize="14sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#EEEEEE" />
</androidx.appcompat.widget.LinearLayoutCompat>
\ No newline at end of file
<com.google.android.gms.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#D9D9D9"
android:baselineAligned="false"
android:minHeight="40dp"
android:orientation="horizontal"
android:paddingHorizontal="5dp"
android:paddingVertical="2dp">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<com.google.android.gms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_width="80dp"
android:layout_height="60dp"
android:layout_gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:background="@color/black"
android:padding="2dp"
android:text="Ad"
android:textColor="@color/white"
android:textSize="8sp"
tools:ignore="HardcodedText,SmallSp" />
</FrameLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginHorizontal="5dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/ad_headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="2"
android:textColor="@color/black"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/ad_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/black"
android:textSize="14sp"
tools:ignore="SmallSp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/ad_app_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_horizontal"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/ad_call_to_action"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginHorizontal="8dp"
android:layout_marginVertical="5dp"
android:background="@drawable/bg_355bea_10"
android:gravity="center"
android:textColor="@color/white"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
\ No newline at end of file
{"nm":"finish","ddd":0,"h":1280,"w":720,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":4,"nm":"形状图层 4","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-4,-66,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[357,551.5,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[-18],"t":36},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[18],"t":44},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[-12],"t":52},{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":1},"s":[10],"t":60},{"s":[0],"t":68}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":36},{"s":[100],"t":44}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"形状 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"路径 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-73.52,-119.272],[-9.086,-46.073],[49,-101]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"描边 1","lc":2,"lj":2,"ml":1,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"修剪路径 1","ix":2,"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":-18,"ix":3},"s":{"a":0,"k":36,"ix":1},"m":1}],"ind":1},{"ty":4,"nm":"形状图层 8","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[3,-92,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[360,543,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"椭圆 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"椭圆路径 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[162,162],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"描边 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3,-92],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"修剪路径 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[29],"t":26},{"s":[100],"t":31}],"ix":2},"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":0},{"s":[720],"t":31}],"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1}],"ind":2}],"v":"5.5.7","fr":30,"op":90,"ip":0,"assets":[]}
\ 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