添加版本下载代码
This commit is contained in:
parent
201a60cf65
commit
36e2b55b07
@ -20,6 +20,7 @@ import androidx.annotation.RequiresPermission
|
|||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.blankj.utilcode.constant.PermissionConstants
|
import com.blankj.utilcode.constant.PermissionConstants
|
||||||
|
import com.blankj.utilcode.util.AppUtils
|
||||||
import com.blankj.utilcode.util.FileUtils
|
import com.blankj.utilcode.util.FileUtils
|
||||||
import com.blankj.utilcode.util.GsonUtils
|
import com.blankj.utilcode.util.GsonUtils
|
||||||
import com.blankj.utilcode.util.LogUtils
|
import com.blankj.utilcode.util.LogUtils
|
||||||
@ -46,6 +47,7 @@ import com.zs.smarthuman.sherpa.VoiceState
|
|||||||
import com.zs.smarthuman.toast.Toaster
|
import com.zs.smarthuman.toast.Toaster
|
||||||
import com.zs.smarthuman.utils.AudioDebugUtil
|
import com.zs.smarthuman.utils.AudioDebugUtil
|
||||||
import com.zs.smarthuman.utils.AudioPcmUtil
|
import com.zs.smarthuman.utils.AudioPcmUtil
|
||||||
|
import com.zs.smarthuman.utils.DangerousUtils
|
||||||
|
|
||||||
import com.zs.smarthuman.utils.UnityPlayerHolder
|
import com.zs.smarthuman.utils.UnityPlayerHolder
|
||||||
import com.zs.smarthuman.utils.ViewSlideAnimator
|
import com.zs.smarthuman.utils.ViewSlideAnimator
|
||||||
@ -55,10 +57,12 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import rxhttp.awaitResult
|
import rxhttp.awaitResult
|
||||||
import rxhttp.toAwaitString
|
import rxhttp.toAwaitString
|
||||||
|
import rxhttp.toDownloadFlow
|
||||||
import rxhttp.wrapper.param.RxHttp
|
import rxhttp.wrapper.param.RxHttp
|
||||||
import rxhttp.wrapper.param.toAwaitResponse
|
import rxhttp.wrapper.param.toAwaitResponse
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -449,6 +453,42 @@ class MainActivity : BaseViewModelActivity<ActivityMainBinding, MainViewModel>()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载并且安装
|
||||||
|
*/
|
||||||
|
private suspend fun downloadApk(apkUrl: String) {
|
||||||
|
val destPath =
|
||||||
|
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.path + "/" + "smartHuman.apk"
|
||||||
|
RxHttp.get(apkUrl)
|
||||||
|
.toDownloadFlow(destPath)
|
||||||
|
.onProgress {
|
||||||
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}.catch {
|
||||||
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}.collect {
|
||||||
|
//下载完成
|
||||||
|
if (AppUtils.isAppRoot()) {
|
||||||
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
DangerousUtils.installAppSilent(it, "-r")
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
AppUtils.installApp(it)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|||||||
383
app/src/main/java/com/zs/smarthuman/utils/DangeroutUtils.kt
Normal file
383
app/src/main/java/com/zs/smarthuman/utils/DangeroutUtils.kt
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
package com.zs.smarthuman.utils
|
||||||
|
|
||||||
|
import android.Manifest.permission
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.PowerManager
|
||||||
|
import android.telephony.SmsManager
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresPermission
|
||||||
|
import com.blankj.utilcode.util.IntentUtils
|
||||||
|
import com.blankj.utilcode.util.LogUtils
|
||||||
|
import com.blankj.utilcode.util.ShellUtils
|
||||||
|
import com.blankj.utilcode.util.Utils
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.jvm.javaClass
|
||||||
|
import kotlin.jvm.javaPrimitiveType
|
||||||
|
import kotlin.text.contains
|
||||||
|
import kotlin.text.toLowerCase
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* author: Blankj
|
||||||
|
* blog : http://blankj.com
|
||||||
|
* time : 2019/06/29
|
||||||
|
* desc :
|
||||||
|
</pre> *
|
||||||
|
*/
|
||||||
|
class DangerousUtils private constructor() {
|
||||||
|
companion object {
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// AppUtils
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Install the app silently.
|
||||||
|
*
|
||||||
|
* Without root permission must hold
|
||||||
|
* `android:sharedUserId="android.uid.shell"` and
|
||||||
|
* `<uses-permission android:name="android.permission.INSTALL_PACKAGES" />`
|
||||||
|
*
|
||||||
|
* @param filePath The path of file.
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
fun installAppSilent(filePath: String): Boolean {
|
||||||
|
return installAppSilent(getFileByPath(filePath), null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the app silently.
|
||||||
|
*
|
||||||
|
* Without root permission must hold
|
||||||
|
* `android:sharedUserId="android.uid.shell"` and
|
||||||
|
* `<uses-permission android:name="android.permission.INSTALL_PACKAGES" />`
|
||||||
|
*
|
||||||
|
* @param filePath The path of file.
|
||||||
|
* @param params The params of installation(e.g.,`-r`, `-s`).
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
fun installAppSilent(filePath: String, params: String?): Boolean {
|
||||||
|
return installAppSilent(getFileByPath(filePath), params)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Install the app silently.
|
||||||
|
*
|
||||||
|
* Without root permission must hold
|
||||||
|
* `android:sharedUserId="android.uid.shell"` and
|
||||||
|
* `<uses-permission android:name="android.permission.INSTALL_PACKAGES" />`
|
||||||
|
*
|
||||||
|
* @param file The file.
|
||||||
|
* @param params The params of installation(e.g.,`-r`, `-s`).
|
||||||
|
* @param isRooted True to use root, false otherwise.
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Install the app silently.
|
||||||
|
*
|
||||||
|
* Without root permission must hold
|
||||||
|
* `android:sharedUserId="android.uid.shell"` and
|
||||||
|
* `<uses-permission android:name="android.permission.INSTALL_PACKAGES" />`
|
||||||
|
*
|
||||||
|
* @param file The file.
|
||||||
|
* @param params The params of installation(e.g.,`-r`, `-s`).
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Install the app silently.
|
||||||
|
*
|
||||||
|
* Without root permission must hold
|
||||||
|
* `android:sharedUserId="android.uid.shell"` and
|
||||||
|
* `<uses-permission android:name="android.permission.INSTALL_PACKAGES" />`
|
||||||
|
*
|
||||||
|
* @param file The file.
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun installAppSilent(
|
||||||
|
file: File?,
|
||||||
|
params: String? = null,
|
||||||
|
isRooted: Boolean = isDeviceRooted
|
||||||
|
): Boolean {
|
||||||
|
if (!isFileExists(file)) return false
|
||||||
|
val filePath = Char.toString() + file!!.absolutePath + '"'
|
||||||
|
val command = ("LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install " +
|
||||||
|
(if (params == null) "" else "$params ")
|
||||||
|
+ filePath)
|
||||||
|
val commandResult = ShellUtils.execCmd(command, isRooted)
|
||||||
|
return if (commandResult.successMsg != null
|
||||||
|
&& commandResult.successMsg.toLowerCase().contains("success")
|
||||||
|
) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
Log.e(
|
||||||
|
"AppUtils", "installAppSilent successMsg: " + commandResult.successMsg +
|
||||||
|
", errorMsg: " + commandResult.errorMsg
|
||||||
|
)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Uninstall the app silently.
|
||||||
|
*
|
||||||
|
* Without root permission must hold
|
||||||
|
* `android:sharedUserId="android.uid.shell"` and
|
||||||
|
* `<uses-permission android:name="android.permission.DELETE_PACKAGES" />`
|
||||||
|
*
|
||||||
|
* @param packageName The name of the package.
|
||||||
|
* @param isKeepData Is keep the data.
|
||||||
|
* @param isRooted True to use root, false otherwise.
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Uninstall the app silently.
|
||||||
|
*
|
||||||
|
* Without root permission must hold
|
||||||
|
* `android:sharedUserId="android.uid.shell"` and
|
||||||
|
* `<uses-permission android:name="android.permission.DELETE_PACKAGES" />`
|
||||||
|
*
|
||||||
|
* @param packageName The name of the package.
|
||||||
|
* @param isKeepData Is keep the data.
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Uninstall the app silently.
|
||||||
|
*
|
||||||
|
* Without root permission must hold
|
||||||
|
* `android:sharedUserId="android.uid.shell"` and
|
||||||
|
* `<uses-permission android:name="android.permission.DELETE_PACKAGES" />`
|
||||||
|
*
|
||||||
|
* @param packageName The name of the package.
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun uninstallAppSilent(
|
||||||
|
packageName: String,
|
||||||
|
isKeepData: Boolean = false,
|
||||||
|
isRooted: Boolean = isDeviceRooted
|
||||||
|
): Boolean {
|
||||||
|
if (isSpace(packageName)) return false
|
||||||
|
val command = ("LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm uninstall "
|
||||||
|
+ (if (isKeepData) "-k " else "")
|
||||||
|
+ packageName)
|
||||||
|
val commandResult = ShellUtils.execCmd(command, isRooted)
|
||||||
|
return if (commandResult.successMsg != null
|
||||||
|
&& commandResult.successMsg.toLowerCase().contains("success")
|
||||||
|
) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
Log.e(
|
||||||
|
"AppUtils", "uninstallAppSilent successMsg: " + commandResult.successMsg +
|
||||||
|
", errorMsg: " + commandResult.errorMsg
|
||||||
|
)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isFileExists(file: File?): Boolean {
|
||||||
|
return file != null && file.exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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 val isDeviceRooted: Boolean
|
||||||
|
private get() {
|
||||||
|
val su = "su"
|
||||||
|
val locations = arrayOf(
|
||||||
|
"/system/bin/",
|
||||||
|
"/system/xbin/",
|
||||||
|
"/sbin/",
|
||||||
|
"/system/sd/xbin/",
|
||||||
|
"/system/bin/failsafe/",
|
||||||
|
"/data/local/xbin/",
|
||||||
|
"/data/local/bin/",
|
||||||
|
"/data/local/",
|
||||||
|
"/system/sbin/",
|
||||||
|
"/usr/bin/",
|
||||||
|
"/vendor/bin/"
|
||||||
|
)
|
||||||
|
for (location in locations) {
|
||||||
|
if (File(location + su).exists()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// DeviceUtils
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Shutdown the device
|
||||||
|
*
|
||||||
|
* Requires root permission
|
||||||
|
* or hold `android:sharedUserId="android.uid.system"`,
|
||||||
|
* `<uses-permission android:name="android.permission.SHUTDOWN" />`
|
||||||
|
* in manifest.
|
||||||
|
*
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
fun shutdown(): Boolean {
|
||||||
|
return try {
|
||||||
|
val result = ShellUtils.execCmd("reboot -p", true)
|
||||||
|
if (result.result == 0) return true
|
||||||
|
Utils.getApp()
|
||||||
|
.startActivity(IntentUtils.getShutdownIntent())
|
||||||
|
true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reboot the device.
|
||||||
|
*
|
||||||
|
* Requires root permission
|
||||||
|
* or hold `android:sharedUserId="android.uid.system"` in manifest.
|
||||||
|
*
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
fun reboot(): Boolean {
|
||||||
|
return try {
|
||||||
|
val result = ShellUtils.execCmd("reboot", true)
|
||||||
|
if (result.result == 0) return true
|
||||||
|
val intent = Intent(Intent.ACTION_REBOOT)
|
||||||
|
intent.putExtra("nowait", 1)
|
||||||
|
intent.putExtra("interval", 1)
|
||||||
|
intent.putExtra("window", 0)
|
||||||
|
Utils.getApp().sendBroadcast(intent)
|
||||||
|
true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reboot the device.
|
||||||
|
*
|
||||||
|
* Requires root permission
|
||||||
|
* or hold `android:sharedUserId="android.uid.system"`,
|
||||||
|
* `<uses-permission android:name="android.permission.REBOOT" />`
|
||||||
|
*
|
||||||
|
* @param reason code to pass to the kernel (e.g., "recovery") to
|
||||||
|
* request special boot modes, or null.
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
fun reboot(reason: String?): Boolean {
|
||||||
|
return try {
|
||||||
|
val pm = Utils.getApp()
|
||||||
|
.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
|
pm.reboot(reason)
|
||||||
|
true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reboot the device to recovery.
|
||||||
|
*
|
||||||
|
* Requires root permission.
|
||||||
|
*
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
fun reboot2Recovery(): Boolean {
|
||||||
|
val result = ShellUtils.execCmd("reboot recovery", true)
|
||||||
|
return result.result == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reboot the device to bootloader.
|
||||||
|
*
|
||||||
|
* Requires root permission.
|
||||||
|
*
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
fun reboot2Bootloader(): Boolean {
|
||||||
|
val result = ShellUtils.execCmd("reboot bootloader", true)
|
||||||
|
return result.result == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable mobile data.
|
||||||
|
*
|
||||||
|
* Must hold `android:sharedUserId="android.uid.system"`,
|
||||||
|
* `<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />`
|
||||||
|
*
|
||||||
|
* @param enabled True to enabled, false otherwise.
|
||||||
|
* @return `true`: success<br></br>`false`: fail
|
||||||
|
*/
|
||||||
|
@RequiresPermission(permission.MODIFY_PHONE_STATE)
|
||||||
|
fun setMobileDataEnabled(enabled: Boolean): Boolean {
|
||||||
|
try {
|
||||||
|
val tm = Utils.getApp()
|
||||||
|
.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
tm.isDataEnabled = enabled
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val setDataEnabledMethod = tm.javaClass.getDeclaredMethod(
|
||||||
|
"setDataEnabled",
|
||||||
|
Boolean::class.javaPrimitiveType
|
||||||
|
)
|
||||||
|
setDataEnabledMethod.invoke(tm, enabled)
|
||||||
|
return true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("NetworkUtils", "setMobileDataEnabled: ", e)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send sms silently.
|
||||||
|
*
|
||||||
|
* Must hold `<uses-permission android:name="android.permission.SEND_SMS" />`
|
||||||
|
*
|
||||||
|
* @param phoneNumber The phone number.
|
||||||
|
* @param content The content.
|
||||||
|
*/
|
||||||
|
@SuppressLint("UnspecifiedImmutableFlag")
|
||||||
|
@RequiresPermission(permission.SEND_SMS)
|
||||||
|
fun sendSmsSilent(phoneNumber: String?, content: String) {
|
||||||
|
if (TextUtils.isEmpty(content)) return
|
||||||
|
val sentIntent = PendingIntent.getBroadcast(
|
||||||
|
Utils.getApp(),
|
||||||
|
0,
|
||||||
|
Intent("send"),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
val smsManager = SmsManager.getDefault()
|
||||||
|
if (content.length >= 70) {
|
||||||
|
val ms: List<String> = smsManager.divideMessage(content)
|
||||||
|
for (str in ms) {
|
||||||
|
smsManager.sendTextMessage(phoneNumber, null, str, sentIntent, null)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
smsManager.sendTextMessage(phoneNumber, null, content, sentIntent, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
throw kotlin.UnsupportedOperationException("u can't instantiate me...")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user