yijianlianUI/app/src/main/java/com/yingmao/clash/act/SplashActivity.kt

662 lines
27 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.yingmao.clash.act
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.text.TextUtils
import android.util.Log
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.yingmao.clash.view.dialog.RxDialogSureCancel
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.luozm.captcha.Captcha
import com.yingmao.clash.net.http.entity.RegisterRsp
import com.orhanobut.logger.Logger
import com.tencent.mmkv.MMKV
import com.yingmao.clash.BuildConfig
import com.yingmao.clash.R
import com.yingmao.clash.app.MainApplication
import com.yingmao.clash.base.BaseActivity
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.conf.BZYConstants.Companion.MMKV_KEY_IS_REGISTER
import com.yingmao.clash.conf.BZYConstants.Companion.MMKV_KEY_NOTE_DEFAULT_PSW
import com.yingmao.clash.conf.BZYConstants.Companion.MMKV_KEY_REMEMBER_PASSWORD
import com.yingmao.clash.conf.BZYConstants.Companion.MMKV_KEY_REMEMBER_USERNAME
import com.yingmao.clash.conf.Conf
import com.yingmao.clash.entity.CheckLoginRsp
import com.yingmao.clash.listener.AsyncCallback
import com.yingmao.clash.net.http.HttpReqType
import com.yingmao.clash.net.http.HttpStatus
import com.yingmao.clash.net.http.entity.LoginRsp
import com.yingmao.clash.net.http.entity.RegisterRspOld
import com.yingmao.clash.net.http.entity.SubscriptionRsp
import com.yingmao.clash.service.ClashManager
import com.yingmao.clash.service.model.Profile
import com.yingmao.clash.service.remote.IClashManager
import com.yingmao.clash.service.remote.wrap
import com.yingmao.clash.util.AESUtil
import com.yingmao.clash.util.Utils
import com.yingmao.clash.util.withProfile
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.vm.SplashAtyVM
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.*
import kotlin.collections.HashSet
class SplashActivity : BaseActivity() {
private val deniedPermissions = hashSetOf<String>()
private val mPermissions = hashSetOf<String>()
private val PERMISSION_REQUEST_CODE: Int = 1
private val PERMISSION_SETTING_REQUEST_CODE = 2
private lateinit var rlPb: View
private lateinit var ll_action: View
private lateinit var username: String
private lateinit var splashAtyVM: SplashAtyVM
override fun onCreate(savedInstanceState: Bundle?) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
super.onCreate(savedInstanceState)
username = Utils.getUniqueID(this)
// var username2 = Utils.getUniqueID2(this);
// com.yingmao.clash.common.log.Log.d("username==>" + username + ", username2==>" + username2)
splashAtyVM = ViewModelProvider(this).get(SplashAtyVM::class.java)
observe(this, splashAtyVM)
setContentView(R.layout.layout_splash_activity)
rlPb = findViewById(R.id.rl_pb)
ll_action = findViewById(R.id.ll_action)
// mPermissions.add(Manifest.permission.READ_PHONE_STATE)
// mPermissions.add(Manifest.permission.INTERNET)
// mPermissions.add(Manifest.permission.ACCESS_NETWORK_STATE)
// if (checkPermissions(mPermissions)) {//权限请求通过
// Log.e("gg", "per sss")
// } else {//权限请求未通过
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// requestPermissions(mPermissions.toTypedArray(), PERMISSION_REQUEST_CODE)
// }
// }
var clashBinder = MainApplication.getApp()?.let {
ClashManager(it).wrap() as IClashManager
}
clashBinder?.let { cb ->
var signList =
AESUtil.getSingInfo(this@SplashActivity, BuildConfig.applicationId, AESUtil.SHA256)
if (signList.isNotEmpty()) {
var si = signList[0]
var ss1 = cb.getSS1(si)
var ss2 = cb.getSS2(si)
com.yingmao.clash.common.log.Log.d("si==>${si}, ss1==>${ss1}, ss2==>${ss2}")
AESUtil.KEY2 = ss1
AESUtil.IV2 = ss2
val routerSet =
MMKV.defaultMMKV().decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST)
if (routerSet != null && routerSet.size > 0) {
isNeedRegister()
} else {
if (BuildConfig.productId == "182265") { //太子没有备用域名所以无需调用getHost
isNeedRegister()
} else {
splashAtyVM.getHost(object : AsyncCallback {
override suspend fun suc() {
Log.e("data", "getHost suc")
MainScope().launch {
isNeedRegister()
}
}
override fun err() {
Log.e("data", "getHost err")
}
})
}
}
}
}
// val Sgtr= AESUtil.decrypt("DCBF7D3857DB252D9D07265D9EB7F2CF2DD5B6070C6BF6B4EC88A1452B8C30834BBC82465ECD117CAA816E18AF526EBA5749AFA0E504F7EE178912BAFAA308268326299157402233C4C3D7319B1843C680C340F137060762ED370DE8DDB5516A51DE118EE83C6C556B579D2C7B1612D98C64153D11334425298E096461A899DF")
//
// println("Sgtr==>$Sgtr")
}
private fun checkPermission(): Boolean {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_NETWORK_STATE
) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
this,
Manifest.permission.INTERNET
) == PackageManager.PERMISSION_GRANTED
) {
return true
}
return false
}
override fun onStarted() {
super.onStarted()
}
private fun graphicVerificationDialog() {
//开启人机验证
MaterialDialog(this).show {
this.cancelable(false)
cornerRadius(res = R.dimen.dp_10)
customView(
R.layout.graphic_verification_dialog_layout,
scrollable = false,
noVerticalPadding = true,
horizontalPadding = false
)
val captchaSimple = findViewById<Captcha>(R.id.captCha)
captchaSimple.setBitmap(R.drawable.gv_icon)
captchaSimple.setCaptchaListener(object : Captcha.CaptchaListener {
override fun onAccess(time: Long): String {
Toast.makeText(this@SplashActivity, "验证成功", Toast.LENGTH_SHORT).show()
dismiss()
val intent = Intent(this@SplashActivity, LoginActivity::class.java)
startActivity(intent)
finish()
return "验证通过,耗时" + time + "毫秒"
}
override fun onFailed(failedCount: Int): String {
Toast.makeText(this@SplashActivity, "验证失败", Toast.LENGTH_SHORT).show()
return "验证失败,已失败" + failedCount + "" + " 注意超过3次验证失败即退出应用"
}
override fun onMaxFailed(): String {
Toast.makeText(
this@SplashActivity,
"验证超过次数,即将退出应用",
Toast.LENGTH_SHORT
)
.show()
finish()
return "验证失败,即将推出登录"
}
})
}
}
private fun isNeedRegister() {
if (!BuildConfig.is_free && BuildConfig.productId.isNotEmpty()) { //渠道包都自动注册登录广州22222也是非自动注册
rlPb.visibility = View.VISIBLE
if (MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_IS_REGISTER, false)) {
splashAtyVM.checkLogin()
} else {
// doRegister()
doRegisterByEncryption()
}
} else {//非渠道自由包
val token = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_TOKEN)
ll_action.visibility = View.VISIBLE
if (MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_IS_REGISTER, false)) {
if (token != null && token.isNotEmpty()) {
ll_action.visibility = View.GONE
rlPb.visibility = View.VISIBLE
splashAtyVM.checkLogin()
} else {
val intent = Intent(this@SplashActivity, LoginActivity::class.java)
startActivity(intent)
finish()
}
} else {
findViewById<View>(R.id.rl_action_login).setOnClickListener {//点有账号直接登录的
val intent = Intent(this@SplashActivity, LoginActivity::class.java)
startActivity(intent)
finish()
}
findViewById<View>(R.id.rl_action_register).setOnClickListener {//无账号的自动注册但不会填任何渠道号
val intent = Intent(this@SplashActivity, RegisterActivity::class.java)
startActivity(intent)
finish()
}
}
}
}
var errorTotal: Int = 0
fun doRegister() {
val params: Map<String, String> = mutableMapOf(
"phoneNumber" to username,
"password" to BZYConstants.defaultPassword,
"checkPassword" to BZYConstants.defaultPassword,
"id" to BuildConfig.productId,
"clientIp" to Utils.getIPAddress(),
"from" to "5",
)
splashAtyVM.register(params)
}
fun doRegisterByEncryption() {
var req_json = JsonObject()
req_json.addProperty("phoneNumber", username)
req_json.addProperty("password", BZYConstants.defaultPassword)
req_json.addProperty("checkPassword", BZYConstants.defaultPassword)
req_json.addProperty("id", BuildConfig.productId)
req_json.addProperty("clientIp", Utils.getIPAddress())
req_json.addProperty("from", "5")
var data = AESUtil.byteArrayToHexStr(
AESUtil.encrypt(req_json.toString())
)
val params: Map<String, String> = mutableMapOf(
"data" to data
)
splashAtyVM.registerByEncryption(params)
}
// private fun initSub() {
// var yaml = context?.getString(com.yingmao.clash.service.R.string.configuration_yaml)
// Log.d(Conf.TAG, "initSub: $yaml")
//
// accelerateViewModel.statusData.observe(viewLifecycleOwner) {
// when (it) {
// is HttpStatus.Loading -> {
//
// Log.d(Conf.TAG, "正在获取节点信息...")
// }
//
// is HttpStatus.Success -> {
//
// val data = it.rsp as SubscriptionRsp
// if (data.code == "1000") {
//
// } else {
//// dismissDialog()
// RxToast.error("获取节点失败:${data.msg}")
// }
//
// data.data?.let { url ->
// Log.e("Data", "机场URL=${url}")
// if (url.isNotEmpty()) {
//// lifecycleScope.launch {
////
//// }
//// sendMessage(1, url)
// setSub(url)
//
// }
// }
//
//// }
// }
//
// is HttpStatus.Failure -> {
// if (it.reqType == HttpReqType.GET_AIRNODES) {
//// dismissDialog()
//// showRetryDialog()
// Logger.e("获取节点异常:${it.msg}")
// }
// }
// }
// }
// }
// private fun setSub(url: String) {
// com.yingmao.clash.common.log.Log.d("setSub....")
//
// lifecycleScope.launch (Dispatchers.IO) {
// com.yingmao.clash.common.log.Log.d("setSub....11")
// withProfile {
// com.yingmao.clash.common.log.Log.d("setSub....2")
// val pro = queryAll().find {
// it.name == "八爪猫"
// }
//
// if (pro == null) {
// com.yingmao.clash.common.log.Log.d("setSub.... pro is null")
// var uuid: UUID = create(Profile.Type.Url, "八爪猫")
// delay(500)
// queryByUUID(uuid)?.let { qPro ->
// setActive(qPro)
// patch(
// qPro.uuid, qPro.name,
//// "https://mojie0201.xn--8stx8olrwkucjq3b.com/api/v1/client/subscribe?token=169110d2674c49604b7e5b5cea341579",
//// "https://www.otcopusapp.cc/lx3af288h5i8pz380/api/v1/client/subscribe?token=d6bc98c7ea53099fa5bd1a3ea415ebb6",
// url, 1800000L
// )
//// coroutineScope {
// commit(qPro.uuid) { status ->
// Log.d(
// Conf.TAG,
// "new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress
// )
// }
// newUuid = qPro.uuid.toString();
// isSubed = true
//// }
// }
// } else {
// Log.d(Conf.TAG, "pro 已存在 ==>" + Gson().toJson(pro))
// setActive(pro)
//// update(pro.uuid)
// newUuid = pro.uuid.toString();
// isSubed = true
// }
// profile = pro;
// }
// }
//
// }
override fun httpSuccess(httpStatus: HttpStatus.Success) {
when (httpStatus.reqType) {
HttpReqType.REGISTER -> {
with(httpStatus.rsp as RegisterRsp) {
if (code == "10000" || code == "200") {
MMKV.defaultMMKV().encode(MMKV_KEY_REMEMBER_USERNAME, username)
MMKV.defaultMMKV()
.encode(MMKV_KEY_REMEMBER_PASSWORD, BZYConstants.defaultPassword)
MMKV.defaultMMKV().encode(MMKV_KEY_IS_REGISTER, true)
MMKV.defaultMMKV().encode(MMKV_KEY_NOTE_DEFAULT_PSW, true)
val encryName = AESUtil.byteArrayToHexStr(
AESUtil.encrypt(username)
)
val encryPsw = AESUtil.byteArrayToHexStr(
AESUtil.encrypt(BZYConstants.defaultPassword)
)
splashAtyVM.login(encryName, encryPsw)
} else if (code == "20062") {
message?.let {
RxToast.error(it)
}
// if (data != null) {
//
// var jo =
// Gson().fromJson<JsonObject>(data, JsonObject::class.java)
// var userName = jo.get("data").asString;
// if (!TextUtils.isEmpty(userName)) {
//
// }
// }
MMKV.defaultMMKV().encode(MMKV_KEY_REMEMBER_USERNAME, username)
graphicVerificationDialog()
} else {
MaterialDialog(this@SplashActivity).show {
message(text = "初始化失败")
positiveButton(R.string.retry) {
// doRegister()
doRegisterByEncryption()
}
negativeButton(R.string.cancel) {
it.dismiss()
finish()
}
}
}
}
}
HttpReqType.LOGIN -> {
val rsp = httpStatus.rsp
if (rsp is LoginRsp) {
if (rsp.code == "1000") {
val mmkv = MMKV.defaultMMKV()
com.yingmao.clash.common.log.Log.i(" HttpReqType.LOGIN token ==> ${rsp.data?.vpnToken}")
mmkv.encode(BZYConstants.MMKV_KEY_TOKEN, rsp.data?.vpnToken)
mmkv.encode(BZYConstants.MMKV_KEY_PH_TOKEN, rsp.data?.phToken)
mmkv.encode(BZYConstants.MMKV_KEY_USER_ID, rsp.data?.userId)
mmkv.encode(MMKV_KEY_REMEMBER_USERNAME, username)
splashAtyVM.checkLogin()
} else {
MaterialDialog(this@SplashActivity).show {
message(text = "初始化失败")
positiveButton(R.string.retry) {
val encryName = AESUtil.byteArrayToHexStr(
AESUtil.encrypt(username)
)
val encryPsw = AESUtil.byteArrayToHexStr(
AESUtil.encrypt(BZYConstants.defaultPassword)
)
splashAtyVM.login(encryName, encryPsw)
}
negativeButton(R.string.cancel) {
it.dismiss()
finish()
}
}
}
}
}
HttpReqType.CHECK_LOGIN -> {
(httpStatus.rsp as CheckLoginRsp).let { checkLoginRsp ->
if (checkLoginRsp.code == 0) {
com.yingmao.clash.common.log.Log.d("splash CHECK_LOGIN==>")
checkLoginRsp.data?.let { MainApplication.setUserInfo(it) }
val expired = checkLoginRsp.data?.expired
val isPerfect = checkLoginRsp.data?.isPerfect
val userCommand = checkLoginRsp.data?.userCommand
val mmkv = MMKV.defaultMMKV()
mmkv.encode(BZYConstants.MMKV_KEY_VPN_EXPIRED, expired ?: true)
mmkv.encode(
BZYConstants.MMKV_KEY_VPN_VALID_PERIOD,
checkLoginRsp.data?.vpnExpireTime ?: 0
)
mmkv.encode(BZYConstants.MMKV_KEY_IS_PERFECT, isPerfect ?: true)
mmkv.encode(BZYConstants.MMKV_KEY_VPN_UserCommand, userCommand ?: "")
toMainPage()
} else {
toLoginPage()
}
}
}
else -> {}
}
}
override fun httpFailure(httpStatus: HttpStatus.Failure) {
when (httpStatus.reqType) {
HttpReqType.REGISTER -> {
com.yingmao.clash.common.log.Log.d("httpFailure HttpReqType.REGISTER")
if (Utils.switchServer()) {//切换服务器并直接重试
// doRegister()
doRegisterByEncryption()
} else {
MaterialDialog(this@SplashActivity).show {
message(text = "初始化失败")
positiveButton(R.string.retry) {
// doRegister()
doRegisterByEncryption()
}
negativeButton(R.string.cancel) {
it.dismiss()
finish()
}
}
}
}
HttpReqType.LOGIN -> {
MaterialDialog(this@SplashActivity).show {
message(text = "初始化失败")
positiveButton(R.string.confirm) {
val encryName = AESUtil.byteArrayToHexStr(
AESUtil.encrypt(username)
)
val encryPsw = AESUtil.byteArrayToHexStr(
AESUtil.encrypt(BZYConstants.defaultPassword)
)
splashAtyVM.login(encryName, encryPsw)
}
negativeButton(R.string.cancel) {
it.dismiss()
finish()
}
}
}
HttpReqType.CHECK_LOGIN -> {
com.yingmao.clash.common.log.Log.d("httpFailure HttpReqType.CHECK_LOGIN")
if (Utils.switchServer()) {
splashAtyVM.checkLogin()
} else {
toLoginPage()
}
}
else -> {}
}
}
//申请权限
private fun checkPermissions(permissions: HashSet<String>): Boolean {
for (permission in permissions) {
val permissionStatus = ContextCompat.checkSelfPermission(this, permission)
if (permissionStatus == PackageManager.PERMISSION_DENIED)
deniedPermissions.add(permission)
else
deniedPermissions.remove(permission)
}
return deniedPermissions.isEmpty()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
Log.e("data", "onRequestPermissionsResult requestCode==> " + requestCode)
permissions.forEach {
Log.e("data", "onRequestPermissionsResult permissions ==> " + it)
}
grantResults.forEach {
Log.e("data", "onRequestPermissionsResult grantResults==> " + it)
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
//
val deniedAndNoLongerPromptPermissions = HashSet<String>()
if (requestCode == PERMISSION_REQUEST_CODE) {
for ((i, permission) in permissions.withIndex()) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(
this,
permission
)
) //不在提示权限包含 已通过的和勾选不在提示的权限
if (grantResults[i] == 0)
deniedAndNoLongerPromptPermissions.remove(permission)
else
deniedAndNoLongerPromptPermissions.add(permission)
else
deniedAndNoLongerPromptPermissions.remove(permission)
}
}
if (deniedAndNoLongerPromptPermissions.isNotEmpty()) {
if (checkPermissions(mPermissions)) {
isNeedRegister() //TODO
return
}
val deniedAndNoLongerPromptPermissionsName = StringBuilder()
for (deniedAndNoLongerPromptPermission in deniedAndNoLongerPromptPermissions) {
when (deniedAndNoLongerPromptPermission) {
// Manifest.permission.WRITE_EXTERNAL_STORAGE -> {
// if (deniedPermissions.contains(deniedAndNoLongerPromptPermission))
// deniedAndNoLongerPromptPermissionsName.append("【存储】")
// else
// deniedAndNoLongerPromptPermissions.remove(
// deniedAndNoLongerPromptPermission
// )
// }
Manifest.permission.READ_PHONE_STATE -> {
if (deniedPermissions.contains(deniedAndNoLongerPromptPermission))
deniedAndNoLongerPromptPermissionsName.append("【手机信息】")
else
deniedAndNoLongerPromptPermissions.remove(
deniedAndNoLongerPromptPermission
)
}
Manifest.permission.ACCESS_WIFI_STATE -> {
if (deniedPermissions.contains(deniedAndNoLongerPromptPermission))
deniedAndNoLongerPromptPermissionsName.append("【访问WIFI信息】")
else
deniedAndNoLongerPromptPermissions.remove(
deniedAndNoLongerPromptPermission
)
}
}
}
val rxDialogSureCancel = RxDialogSureCancel(this)
rxDialogSureCancel.setContent("需要${deniedAndNoLongerPromptPermissionsName}权限,由于您设置了不再提示,需要手动开启权限!")
rxDialogSureCancel.setCancelListener {
rxDialogSureCancel.cancel()
finish()
}
rxDialogSureCancel.setSureListener {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivityForResult(intent, PERMISSION_SETTING_REQUEST_CODE)
}
rxDialogSureCancel.show()
Logger.i("${deniedAndNoLongerPromptPermissions.size}需要${deniedAndNoLongerPromptPermissionsName.toString()}权限,由于您设置了不再提示,需要手动开启权限!")
} else {
if (checkPermissions(mPermissions)) {
isNeedRegister() //TODO
} else {
finish()
}
}
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PERMISSION_SETTING_REQUEST_CODE) {
if (checkPermissions(mPermissions)) {
isNeedRegister() //TODO
} else {
requestPermissions(deniedPermissions.toTypedArray(), PERMISSION_REQUEST_CODE)
}
}
}
private fun toMainPage() {
val intent = Intent(this, NewMainActivity::class.java)
startActivity(intent)
finish()
}
private fun toLoginPage() {
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
finish()
}
}