|
|
|
@ -1,11 +1,17 @@ |
|
|
|
|
package top.niunaijun.blackdex.view.main |
|
|
|
|
|
|
|
|
|
import android.Manifest |
|
|
|
|
import android.content.Intent |
|
|
|
|
import android.content.pm.PackageManager |
|
|
|
|
import android.net.Uri |
|
|
|
|
import android.os.Build |
|
|
|
|
import android.os.Bundle |
|
|
|
|
import android.provider.Settings |
|
|
|
|
import android.view.Menu |
|
|
|
|
import android.view.MenuItem |
|
|
|
|
import android.view.inputmethod.InputMethodManager |
|
|
|
|
import androidx.activity.result.contract.ActivityResultContracts |
|
|
|
|
import androidx.annotation.RequiresApi |
|
|
|
|
import androidx.lifecycle.ViewModelProvider |
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager |
|
|
|
|
import com.afollestad.materialdialogs.MaterialDialog |
|
|
|
@ -14,6 +20,7 @@ import com.roger.catloadinglibrary.CatLoadingView |
|
|
|
|
import top.niunaijun.blackbox.BlackDexCore |
|
|
|
|
import top.niunaijun.blackbox.core.system.dump.IBDumpMonitor |
|
|
|
|
import top.niunaijun.blackbox.entity.dump.DumpResult |
|
|
|
|
import top.niunaijun.blackbox.utils.compat.BuildCompat |
|
|
|
|
import top.niunaijun.blackdex.R |
|
|
|
|
import top.niunaijun.blackdex.data.entity.AppInfo |
|
|
|
|
import top.niunaijun.blackdex.data.entity.DumpInfo |
|
|
|
@ -48,6 +55,7 @@ class MainActivity : BaseActivity() { |
|
|
|
|
initSearchView() |
|
|
|
|
|
|
|
|
|
BlackDexCore.get().registerDumpMonitor(mMonitor) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun initView() { |
|
|
|
@ -56,6 +64,11 @@ class MainActivity : BaseActivity() { |
|
|
|
|
viewBinding.recyclerView.layoutManager = LinearLayoutManager(this) |
|
|
|
|
|
|
|
|
|
mAdapter.setOnItemClick { _, _, data -> |
|
|
|
|
if (viewBinding.searchView.isSearchOpen) { |
|
|
|
|
viewBinding.searchView.closeSearch() |
|
|
|
|
filterApp("") |
|
|
|
|
} |
|
|
|
|
hideKeyboard() |
|
|
|
|
viewModel.startDexDump(data.packageName) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -65,10 +78,10 @@ class MainActivity : BaseActivity() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun initViewModel() { |
|
|
|
|
viewModel = ViewModelProvider(this, InjectionUtil.getMainFactory()).get(MainViewModel::class.java) |
|
|
|
|
viewModel.getAppList() |
|
|
|
|
|
|
|
|
|
viewModel = |
|
|
|
|
ViewModelProvider(this, InjectionUtil.getMainFactory()).get(MainViewModel::class.java) |
|
|
|
|
viewBinding.stateView.showLoading() |
|
|
|
|
viewModel.getAppList() |
|
|
|
|
|
|
|
|
|
viewModel.mAppListLiveData.observe(this) { |
|
|
|
|
it?.let { |
|
|
|
@ -95,7 +108,10 @@ class MainActivity : BaseActivity() { |
|
|
|
|
title(text = "脱壳失败") |
|
|
|
|
message(text = "未知错误,可前往GitHub(https://github.com/CodingGay/BlackDex)提Issue") |
|
|
|
|
negativeButton(text = "Github") { |
|
|
|
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/CodingGay/BlackDex/issues")) |
|
|
|
|
val intent = Intent( |
|
|
|
|
Intent.ACTION_VIEW, |
|
|
|
|
Uri.parse("https://github.com/CodingGay/BlackDex/issues") |
|
|
|
|
) |
|
|
|
|
startActivity(intent) |
|
|
|
|
} |
|
|
|
|
positiveButton(text = "确定") |
|
|
|
@ -126,10 +142,20 @@ class MainActivity : BaseActivity() { |
|
|
|
|
override fun onDump(result: DumpResult?) { |
|
|
|
|
result?.let { |
|
|
|
|
if (result.success) { |
|
|
|
|
viewModel.mDexDumpLiveData.postValue(DumpInfo(DumpInfo.SUCCESS,"DEX文件储存在:${result.dir}")) |
|
|
|
|
viewModel.mDexDumpLiveData.postValue( |
|
|
|
|
DumpInfo( |
|
|
|
|
DumpInfo.SUCCESS, |
|
|
|
|
"DEX文件储存在:${result.dir}" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
viewModel.mDexDumpLiveData.postValue(DumpInfo(DumpInfo.FAIL,"错误原因:${result.msg}")) |
|
|
|
|
viewModel.mDexDumpLiveData.postValue( |
|
|
|
|
DumpInfo( |
|
|
|
|
DumpInfo.FAIL, |
|
|
|
|
"错误原因:${result.msg}" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -138,7 +164,8 @@ class MainActivity : BaseActivity() { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun initSearchView() { |
|
|
|
|
viewBinding.searchView.setOnQueryTextListener(object : SimpleSearchView.OnQueryTextListener { |
|
|
|
|
viewBinding.searchView.setOnQueryTextListener(object : |
|
|
|
|
SimpleSearchView.OnQueryTextListener { |
|
|
|
|
override fun onQueryTextChange(newText: String): Boolean { |
|
|
|
|
filterApp(newText) |
|
|
|
|
return true |
|
|
|
@ -171,17 +198,70 @@ class MainActivity : BaseActivity() { |
|
|
|
|
LoadingUtil.showLoading(loadingView, supportFragmentManager) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun hideKeyboard() { |
|
|
|
|
val imm: InputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager |
|
|
|
|
window.peekDecorView()?.run { |
|
|
|
|
imm.hideSoftInputFromWindow(windowToken, 0) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun requestStoragePermission() { |
|
|
|
|
if (BuildCompat.isM() && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { |
|
|
|
|
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private val openDocumentedResult = registerForActivityResult(ActivityResultContracts.GetContent()) { |
|
|
|
|
private val openDocumentedResult = |
|
|
|
|
registerForActivityResult(ActivityResultContracts.GetContent()) { |
|
|
|
|
it?.run { |
|
|
|
|
viewModel.startDexDump(it.toString()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@RequiresApi(Build.VERSION_CODES.M) |
|
|
|
|
private val requestPermissionLauncher = |
|
|
|
|
registerForActivityResult(ActivityResultContracts.RequestPermission()) { |
|
|
|
|
if (!it) { |
|
|
|
|
MaterialDialog(this).show { |
|
|
|
|
title(text = "申请失败") |
|
|
|
|
message(text = "请授予我们读写本地文件权限,否则软件将无法正常运行。") |
|
|
|
|
|
|
|
|
|
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { |
|
|
|
|
|
|
|
|
|
positiveButton(text = "再次申请") { |
|
|
|
|
requestStoragePermission() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
positiveButton(text = "手动授予") { |
|
|
|
|
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) |
|
|
|
|
val uri = Uri.fromParts("package", packageName, null) |
|
|
|
|
intent.data = uri |
|
|
|
|
try { |
|
|
|
|
startActivity(intent) |
|
|
|
|
} catch (e: Exception) { |
|
|
|
|
e.printStackTrace() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
negativeButton(text = "退出软件") { |
|
|
|
|
finish() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun onStart() { |
|
|
|
|
super.onStart() |
|
|
|
|
requestStoragePermission() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
override fun onBackPressed() { |
|
|
|
|
if (viewBinding.searchView.isSearchOpen) { |
|
|
|
|
viewBinding.searchView.closeSearch() |
|
|
|
|
filterApp("") |
|
|
|
|
} else { |
|
|
|
|
super.onBackPressed() |
|
|
|
|
} |
|
|
|
@ -200,7 +280,8 @@ class MainActivity : BaseActivity() { |
|
|
|
|
override fun onOptionsItemSelected(item: MenuItem): Boolean { |
|
|
|
|
when (item.itemId) { |
|
|
|
|
R.id.main_git -> { |
|
|
|
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/CodingGay/BlackDex")) |
|
|
|
|
val intent = |
|
|
|
|
Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/CodingGay/BlackDex")) |
|
|
|
|
startActivity(intent) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|