Commit d27ca493 authored by liusheng's avatar liusheng

合并分支

parents d823de6c dd2abac2
...@@ -22,21 +22,13 @@ android { ...@@ -22,21 +22,13 @@ android {
} }
} }
// compileSdk 30 // compileSdk 30
// defaultConfig { defaultConfig {
// applicationId = "com.ccwangluo.accelerator" applicationId = "com.ccwangluo.accelerator"
// minSdk 21 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// targetSdk 30
// versionCode = 1 manifestPlaceholders.put("XG_ACCESS_ID","1580009634")
// versionName = "1.0" manifestPlaceholders.put("XG_ACCESS_KEY","AIJKAIYR3WPS")
// }
// testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// javaCompileOptions {
// annotationProcessor(Options {)
// arguments = listOf( moduleName : project.getName() )
// }
// }
// manifestPlaceholders = listOf(qqappid = "你的qq appid")
// }
buildTypes { buildTypes {
named("release"){ named("release"){
...@@ -123,4 +115,5 @@ dependencies { ...@@ -123,4 +115,5 @@ dependencies {
implementation("com.tencent.bugly:crashreport_upgrade:1.5.23")//其中latest.release指代最新版本号,也可以指定明确的版本号,例如1.2.0 implementation("com.tencent.bugly:crashreport_upgrade:1.5.23")//其中latest.release指代最新版本号,也可以指定明确的版本号,例如1.2.0
implementation ("com.tencent.bugly:nativecrashreport:3.9.2")//其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.2.0 implementation ("com.tencent.bugly:nativecrashreport:3.9.2")//其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.2.0
implementation("com.tencent.tpns:tpns:1.3.2.0-release")
} }
\ No newline at end of file
...@@ -170,3 +170,9 @@ ...@@ -170,3 +170,9 @@
-dontwarn com.tencent.bugly.** -dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;} -keep public class com.tencent.bugly.**{*;}
-keep class android.support.**{*;} -keep class android.support.**{*;}
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep class com.tencent.android.tpush.** {*;}
-keep class com.tencent.tpns.baseapi.** {*;}
-keep class com.tencent.tpns.mqttchannel.** {*;}
-keep class com.tencent.tpns.dataacquisition.** {*;}
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.ccwangluo.accelerator"> package="com.ccwangluo.accelerator">
<!-- 【必须】 移动推送 TPNS SDK VIP版本所需权限 -->
<permission
android:name="com.ccwangluo.accelerator.permission.XGPUSH_RECEIVE"
android:protectionLevel="signature" />
<uses-permission android:name="com.ccwangluo.accelerator.permission.XGPUSH_RECEIVE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
...@@ -17,7 +23,6 @@ ...@@ -17,7 +23,6 @@
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- 支持A-GPS辅助定位 --> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- 支持A-GPS辅助定位 -->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <!-- 用于 log 日志 --> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <!-- 用于 log 日志 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- 配置可查询包名, 配置测试游戏必须添加 添加 --> <!-- 配置可查询包名, 配置测试游戏必须添加 添加 -->
...@@ -35,6 +40,7 @@ ...@@ -35,6 +40,7 @@
<package android:name="com.tencent.mm" /> <package android:name="com.tencent.mm" />
<package android:name="com.goplaycn.googleinstall" /> <package android:name="com.goplaycn.googleinstall" />
<package android:name="io.kkzs" /> <package android:name="io.kkzs" />
<package android:name="com.eg.android.AlipayGphone" />
</queries> </queries>
...@@ -69,6 +75,26 @@ ...@@ -69,6 +75,26 @@
android:name="TencentMapSDK" android:name="TencentMapSDK"
android:value="KZFBZ-QJ26J-WAYFC-FIO5N-FE453-QTFTT" /> android:value="KZFBZ-QJ26J-WAYFC-FIO5N-FE453-QTFTT" />
<meta-data
android:name="XG_SERVER_SUFFIX"
android:value="tpns.sh.tencent.com" />
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
<receiver android:name=".receiver.MyXGPushBaseReceiver">
<intent-filter>
<!-- 接收消息透传 -->
<action android:name="com.tencent.android.xg.vip.action.PUSH_MESSAGE" />
<!-- 监听注册、反注册、设置/删除标签、通知被点击等处理结果 -->
<action android:name="com.tencent.android.xg.vip.action.FEEDBACK" />
</intent-filter>
</receiver>
<!-- 在自身应用的AndroidManifest.xml文件中添加如下结点,其中 xxx 为任意自定义名称: -->
<!-- 关闭与 TPNS 应用的联合保活功能,请配置 -->
<provider
android:name="com.tencent.android.tpush.XGPushProvider"
tools:replace="android:authorities"
android:authorities="com.ccwangluo.accelerator.ccwangluo.XGVIP_PUSH_AUTH"
android:exported="false" />
<activity <activity
android:name=".wxapi.WXEntryActivity" android:name=".wxapi.WXEntryActivity"
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
......
...@@ -12,6 +12,7 @@ import com.hjq.toast.ToastUtils ...@@ -12,6 +12,7 @@ import com.hjq.toast.ToastUtils
import com.tencent.bugly.Bugly import com.tencent.bugly.Bugly
import com.tencent.bugly.BuglyStrategy import com.tencent.bugly.BuglyStrategy
import com.tencent.bugly.beta.Beta import com.tencent.bugly.beta.Beta
import com.tencent.android.tpush.XGPushConfig
import com.tencent.map.geolocation.TencentLocationManager import com.tencent.map.geolocation.TencentLocationManager
import com.tencent.mmkv.MMKV import com.tencent.mmkv.MMKV
import com.xuexiang.xpage.PageConfig import com.xuexiang.xpage.PageConfig
...@@ -33,6 +34,7 @@ class App : Application(), androidx.work.Configuration.Provider by Core { ...@@ -33,6 +34,7 @@ class App : Application(), androidx.work.Configuration.Provider by Core {
MultiDex.install(this) MultiDex.install(this)
Core.init(this, MainActivity::class) Core.init(this, MainActivity::class)
MMKV.initialize(this) MMKV.initialize(this)
XGPushConfig.enableDebug(this,true);
} }
fun initBugly(){ fun initBugly(){
......
...@@ -6,8 +6,6 @@ data class NetState( ...@@ -6,8 +6,6 @@ data class NetState(
var accNetDelay: Int, var accNetDelay: Int,
var delay : Int,
//丢包率 //丢包率
var lossRate: String var lossRate: String
......
...@@ -8,7 +8,7 @@ data class News( ...@@ -8,7 +8,7 @@ data class News(
val abbrContent: String?, val abbrContent: String?,
val avatar: String?, val avatar: String?,
val createdDate: String?, val createdDate: String?,
val greatNum: Int?, var greatNum: Int,
val id: Int, val id: Int,
val imgs: String?, val imgs: String?,
var isGreat: Boolean, var isGreat: Boolean,
......
package com.ccwangluo.accelerator.receiver
import android.content.Context
import com.tencent.android.tpush.*
class MyXGPushBaseReceiver : XGPushBaseReceiver (){
override fun onRegisterResult(p0: Context?, p1: Int, p2: XGPushRegisterResult?) {
}
override fun onUnregisterResult(p0: Context?, p1: Int) {
}
override fun onSetTagResult(p0: Context?, p1: Int, p2: String?) {
}
override fun onDeleteTagResult(p0: Context?, p1: Int, p2: String?) {
}
override fun onSetAccountResult(p0: Context?, p1: Int, p2: String?) {
}
override fun onDeleteAccountResult(p0: Context?, p1: Int, p2: String?) {
}
override fun onSetAttributeResult(p0: Context?, p1: Int, p2: String?) {
}
override fun onQueryTagsResult(p0: Context?, p1: Int, p2: String?, p3: String?) {
}
override fun onDeleteAttributeResult(p0: Context?, p1: Int, p2: String?) {
}
override fun onTextMessage(p0: Context?, p1: XGPushTextMessage?) {
}
override fun onNotificationClickedResult(p0: Context?, p1: XGPushClickedResult?) {
}
override fun onNotificationShowedResult(p0: Context?, p1: XGPushShowedResult?) {
}
}
\ No newline at end of file
...@@ -32,11 +32,18 @@ import com.xuexiang.xpage.core.PageOption ...@@ -32,11 +32,18 @@ import com.xuexiang.xpage.core.PageOption
import android.hardware.SensorManager import android.hardware.SensorManager
import android.hardware.SensorEventListener import android.hardware.SensorEventListener
import android.os.Handler import android.os.Handler
import android.util.Log
import com.ccwangluo.accelerator.utils.SysUtils import com.ccwangluo.accelerator.utils.SysUtils
import com.xuexiang.xutil.net.NetworkUtils import com.xuexiang.xutil.net.NetworkUtils
import com.xuexiang.xutil.system.PermissionUtils import com.xuexiang.xutil.system.PermissionUtils
import fm.jiecao.jcvideoplayer_lib.JCVideoPlayer import fm.jiecao.jcvideoplayer_lib.JCVideoPlayer
import java.security.Permission import java.security.Permission
import com.tencent.android.tpush.XGIOperateCallback
import com.tencent.android.tpush.XGPushManager
class MainActivity() : XPageActivity(), TencentLocationListener { class MainActivity() : XPageActivity(), TencentLocationListener {
...@@ -113,6 +120,17 @@ class MainActivity() : XPageActivity(), TencentLocationListener { ...@@ -113,6 +120,17 @@ class MainActivity() : XPageActivity(), TencentLocationListener {
private fun initPhoneUtils() { private fun initPhoneUtils() {
PhoneUtils.getPhoneInfo() PhoneUtils.getPhoneInfo()
//腾讯推送
XGPushManager.registerPush(this, object : XGIOperateCallback {
override fun onSuccess(data: Any, flag: Int) {
//token在设备卸载重装的时候有可能会变
Log.d("TPush", "注册成功,设备token为:$data")
}
override fun onFail(data: Any, errCode: Int, msg: String) {
Log.d("TPush", "注册失败,错误码:$errCode,错误信息:$msg")
}
})
} }
override fun onBackPressed() { override fun onBackPressed() {
......
...@@ -89,18 +89,18 @@ class AccelertorFragment : XPageFragment() { ...@@ -89,18 +89,18 @@ class AccelertorFragment : XPageFragment() {
binding.netLost2Unit.visibility = View.GONE binding.netLost2Unit.visibility = View.GONE
} }
if (it.delay != -1) { if (state == BaseService.State.Connected) {
binding.netQuality.setText(SysUtils.getnetQuality(it.delay)) binding.netQuality.setText(SysUtils.getnetQuality(it.accNetDelay))
} else {
binding.netQuality.setText(SysUtils.getnetQuality(it.preNetDelay))
} }
binding.activeNetwork.setText(SysUtils.getActiveNet()) binding.activeNetwork.setText(SysUtils.getActiveNet())
}) })
accelertorViewModel.accState.observe(this, { accelertorViewModel.accState.observe(this, {
binding.accStateTx.setText(SysUtils.getAccTimeString(acc_timer)) binding.accStateTx.setText(SysUtils.getAccTimeString(acc_timer))
if (it != state) {
state = it state = it
freshData(it) freshData(it)
}
if (SettingSPUtils.isSmartAccOpen) { if (SettingSPUtils.isSmartAccOpen) {
binding.smartAccOpen.setText("已开启") binding.smartAccOpen.setText("已开启")
binding.smartAccOpen.setTextColor(resources.getColor(R.color.open_acc_enable)) binding.smartAccOpen.setTextColor(resources.getColor(R.color.open_acc_enable))
...@@ -135,10 +135,10 @@ class AccelertorFragment : XPageFragment() { ...@@ -135,10 +135,10 @@ class AccelertorFragment : XPageFragment() {
binding.btnQuick.isEnabled = true binding.btnQuick.isEnabled = true
binding.progressViewCircleSmall.progress = 0F binding.progressViewCircleSmall.progress = 0F
binding.progressViewCircleSmall.postDelayed({ binding.progressViewCircleSmall.postDelayed({
if(state != BaseService.State.Connected){ if (state != BaseService.State.Connected) {
ToastUtils.show("加速失败") ToastUtils.show("加速失败")
} }
},3000) }, 3000)
AcceleratorUtils.startAccelerator(this@AccelertorFragment) AcceleratorUtils.startAccelerator(this@AccelertorFragment)
} }
}) })
...@@ -293,12 +293,7 @@ class AccelertorFragment : XPageFragment() { ...@@ -293,12 +293,7 @@ class AccelertorFragment : XPageFragment() {
fun freshData(state: BaseService.State) { fun freshData(state: BaseService.State) {
if (state == BaseService.State.Connected) { if (state == BaseService.State.Connected) {
binding.gamePicIn1.startAnimation(getDefaultAnim()) startAccSuccess()
binding.accStateTx.visibility = View.VISIBLE
binding.btnQuick.setBackgroundResource(R.mipmap.quick_stop)
if (binding.gamePicOut.background is AnimationDrawable) {
(binding.gamePicOut.background as AnimationDrawable).stop()
}
if (SettingSPUtils.isFirstAccSuccess) { if (SettingSPUtils.isFirstAccSuccess) {
context?.let { context?.let {
CommonDialog(it).setTitle("防止加速掉线") CommonDialog(it).setTitle("防止加速掉线")
...@@ -310,7 +305,6 @@ class AccelertorFragment : XPageFragment() { ...@@ -310,7 +305,6 @@ class AccelertorFragment : XPageFragment() {
} }
} }
binding.gameStart.visibility = View.VISIBLE
} else { } else {
binding.gamePicIn1.clearAnimation() binding.gamePicIn1.clearAnimation()
if (binding.gamePicOut.background is AnimationDrawable) { if (binding.gamePicOut.background is AnimationDrawable) {
...@@ -339,7 +333,18 @@ class AccelertorFragment : XPageFragment() { ...@@ -339,7 +333,18 @@ class AccelertorFragment : XPageFragment() {
fun startAnim() { fun startAnim() {
binding.progressViewCircleSmall.startProgressAnimation() binding.progressViewCircleSmall.startProgressAnimation()
}
fun startAccSuccess(){
if (binding.gameStart.visibility == View.GONE) {
binding.gamePicIn1.startAnimation(getDefaultAnim())
binding.accStateTx.visibility = View.VISIBLE
binding.btnQuick.setBackgroundResource(R.mipmap.quick_stop)
if (binding.gamePicOut.background is AnimationDrawable) {
(binding.gamePicOut.background as AnimationDrawable).stop()
}
binding.gameStart.visibility = View.VISIBLE
}
} }
fun getDefaultAnim(): RotateAnimation { fun getDefaultAnim(): RotateAnimation {
......
package com.ccwangluo.accelerator.ui.news package com.ccwangluo.accelerator.ui.news
import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
...@@ -25,6 +27,7 @@ import com.ccwangluo.accelerator.model.NewsModel ...@@ -25,6 +27,7 @@ import com.ccwangluo.accelerator.model.NewsModel
import com.ccwangluo.accelerator.ui.view.RatingBar import com.ccwangluo.accelerator.ui.view.RatingBar
import com.ccwangluo.accelerator.ui.web.CommonWebViewFragment import com.ccwangluo.accelerator.ui.web.CommonWebViewFragment
import com.github.shadowsocks.http.HttpConfig import com.github.shadowsocks.http.HttpConfig
import com.hjq.toast.ToastUtils
class NewsObjectFragment : XPageFragment() { class NewsObjectFragment : XPageFragment() {
...@@ -121,26 +124,32 @@ class NewsObjectFragment : XPageFragment() { ...@@ -121,26 +124,32 @@ class NewsObjectFragment : XPageFragment() {
} }
itemData.isGreat?.let { itemData.isGreat?.let {
if (it) { if (it) {
itemView.findViewById<TextView>(R.id.great_num).setTextColor(Color.parseColor("#3CA4FD"))
itemView.findViewById<ImageView>(R.id.great_img) itemView.findViewById<ImageView>(R.id.great_img)
.setBackgroundResource(R.mipmap.icon_praise_bu) .setBackgroundResource(R.mipmap.icon_praise_bu)
} else { } else {
itemView.findViewById<TextView>(R.id.great_num).setTextColor(Color.parseColor("#FFBBBBBB"))
itemView.findViewById<ImageView>(R.id.great_img) itemView.findViewById<ImageView>(R.id.great_img)
.setBackgroundResource(R.mipmap.icon_praise_ga) .setBackgroundResource(R.mipmap.icon_praise_ga)
} }
} }
itemView.findViewById<ImageView>(R.id.great_img).setOnClickListener { itemView.findViewById<ImageView>(R.id.great_img).setOnClickListener {
itemData.isGreat?.let { itemData.isGreat?.let {
if (it) { newsViewModel?.greate(this@NewsObjectFragment,itemData.type, gameId, itemData.id,it) {
return@setOnClickListener if (!it) {
} ToastUtils.show("点赞成功")
newsViewModel?.greate(itemData.type, gameId, itemData.id, {
itemData.isGreat = true itemData.isGreat = true
itemData.greatNum++
} else {
itemData.isGreat = false
itemData.greatNum--
}
recycle_view?.adapter?.notifyDataSetChanged() recycle_view?.adapter?.notifyDataSetChanged()
}) }
} }
} }
itemView.setOnClickListener { itemView.findViewById<View>(R.id.item_click_view).setOnClickListener {
val params = Bundle() val params = Bundle()
params.putString( params.putString(
CommonWebViewFragment.WEBVIEW_URL_KEY, HttpConfig.UI_MAIN_URL + CommonWebViewFragment.WEBVIEW_URL_KEY, HttpConfig.UI_MAIN_URL +
......
...@@ -4,7 +4,9 @@ import androidx.lifecycle.MutableLiveData ...@@ -4,7 +4,9 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.ccwangluo.accelerator.model.NewsModel import com.ccwangluo.accelerator.model.NewsModel
import com.ccwangluo.accelerator.utils.LoginUtils
import com.ccwangluo.accelerator.utils.http.HttpGo import com.ccwangluo.accelerator.utils.http.HttpGo
import com.xuexiang.xpage.base.XPageFragment
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
...@@ -37,12 +39,17 @@ class NewsObjectModel : ViewModel() { ...@@ -37,12 +39,17 @@ class NewsObjectModel : ViewModel() {
/** /**
* 点赞 * 点赞
*/ */
fun greate(type: Int?,parentId : Int, gameId: Int, callback: () -> Unit) { fun greate(xPageFragment: XPageFragment,type: Int?, gameId: Int, parentId: Int, isGreate: Boolean, callback: () -> Unit) {
val map = mutableMapOf<String, String>() val map = mutableMapOf<String, Any>()
map.put("gameId", gameId.toString()) map.put("gameId", gameId)
map.put("parentId",parentId.toString()) map.put("parentId", parentId)
map.put("isUnGreat", isGreate)
type?.let { type?.let {
map.put("type", it.toString()) map.put("type", it)
}
if (LoginUtils.token == null) {
LoginUtils.login(xPageFragment,{})
return
} }
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val res = val res =
......
...@@ -22,6 +22,7 @@ import com.github.shadowsocks.bg.BaseService ...@@ -22,6 +22,7 @@ import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.http.LineConfig import com.github.shadowsocks.http.LineConfig
import com.github.shadowsocks.net.NetworkManager
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.hjq.toast.ToastUtils import com.hjq.toast.ToastUtils
import com.tencent.mmkv.MMKV import com.tencent.mmkv.MMKV
...@@ -53,12 +54,6 @@ object AcceleratorUtils { ...@@ -53,12 +54,6 @@ object AcceleratorUtils {
//游戏 //游戏
var game: GameInfo? = null var game: GameInfo? = null
//加速前延迟
var pre_net = -1
//加速后延迟
var acc_net = -1
var stateListener: (BaseService.State, Long, NetState?) -> Unit = { state, l, net -> var stateListener: (BaseService.State, Long, NetState?) -> Unit = { state, l, net ->
} }
...@@ -71,7 +66,7 @@ object AcceleratorUtils { ...@@ -71,7 +66,7 @@ object AcceleratorUtils {
val res = HttpGo.getSync<Game>("/api/new/game/list?id=1&page=1&size=1") val res = HttpGo.getSync<Game>("/api/new/game/list?id=1&page=1&size=1")
res?.let { res?.let {
game = it.data?.list?.get(0) game = it.data?.list?.get(0)
withContext(Dispatchers.Main){ withContext(Dispatchers.Main) {
callback(true) callback(true)
} }
game?.let { game?.let {
...@@ -92,42 +87,37 @@ object AcceleratorUtils { ...@@ -92,42 +87,37 @@ object AcceleratorUtils {
context.lifecycleScope.launch(Dispatchers.IO) { context.lifecycleScope.launch(Dispatchers.IO) {
while (true) { while (true) {
game?.let { game?.let {
val split = it.boosterServer.split(":") var net = NetState(-1, -1, "100")
var net = NetState(-1, -1, -1, "100")
net.delay = NetUtils.tcpPing(split[0], split[1].toInt()).toInt()
pre_net = net.delay
if (state == BaseService.State.Connected) { if (state == BaseService.State.Connected) {
val delay = NetUtils.tcpPing(split[0], split[1].toInt(),DataStore.portProxy).toInt() val split = it.boosterServer.split(":")
acc_net = (delay * 0.5).toInt() net.preNetDelay = NetUtils.tcpPing(split[0], split[1].toInt()).toInt()
val delay =
NetUtils.tcpPing(split[0], split[1].toInt(), DataStore.portProxy)
.toInt()
net.accNetDelay = (delay * 0.5).toInt()
LoginUtils.getUserHasTimer { LoginUtils.getUserHasTimer {
if (!it) { //没有加速时长关闭服务 if (!it) { //没有加速时长关闭服务
stopAccelerator() stopAccelerator()
} }
} }
net.delay = if (net.delay < delay) net.delay else delay net.accNetDelay =
if (net.accNetDelay > net.preNetDelay && net.preNetDelay != -1) net.preNetDelay else net.accNetDelay
net.lossRate = if (net.accNetDelay == -1) "100" else "0"
} else { } else {
acc_net = -1 net.accNetDelay = -1
net.lossRate = if (net.preNetDelay == -1) "100" else "0"
} }
net.lossRate = if (net.delay == -1) "100" else "0"
net.preNetDelay = pre_net
net.accNetDelay = acc_net
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
stateListener(state, getAccTime(), net) stateListener(state, getAccTime(), net)
} }
}
delay(2000)
}
}
context.lifecycleScope.launch(Dispatchers.IO) {
while (true) {
stateListener(state, getAccTime(), null)
delay(1000) delay(1000)
} }
} }
} }
}
fun checkVpn() { fun checkVpn() {
if (AuthManager.Last_ACC_TIme == 0L || System.currentTimeMillis() - AuthManager.Last_ACC_TIme > 2 * 3600 * 1000){ if (AuthManager.Last_ACC_TIme == 0L || System.currentTimeMillis() - AuthManager.Last_ACC_TIme > 2 * 3600 * 1000) {
return return
} }
if (SysUtils.isVpn(context) && state != BaseService.State.Connected) { if (SysUtils.isVpn(context) && state != BaseService.State.Connected) {
......
...@@ -39,33 +39,6 @@ object SysUtils { ...@@ -39,33 +39,6 @@ object SysUtils {
} }
} }
/**
* ping 网络状态
*/
suspend fun getNetPing(ip: String): NetState {
var delay: Int = -1
var lost = ""
val p = Runtime.getRuntime().exec("ping -c 4 ${ip}")
val buf = BufferedReader(InputStreamReader(p.inputStream))
var str: String? = String()
while (buf.readLine().also { str = it } != null) {
str?.let {
if (it.contains("packet loss")) {
val i = it.indexOf("received")
val j = it.indexOf("%")
// System.out.println("丢包率:"+str.substring(j-3, j+1));
lost = it.substring(i + 10, j)
}
if (it.contains("avg")) {
val i = it.indexOf("/", 20)
val j = it.indexOf(".", i)
delay = it.substring(i + 1, j).toInt()
}
}
}
return NetState(-1, -1, delay, lost)
}
/* /*
......
...@@ -7,6 +7,7 @@ import com.google.gson.Gson ...@@ -7,6 +7,7 @@ import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.hjq.toast.ToastUtils import com.hjq.toast.ToastUtils
import com.xuexiang.xutil.XUtil import com.xuexiang.xutil.XUtil
import com.umeng.vt.diff.V
import okhttp3.* import okhttp3.*
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
...@@ -82,7 +83,7 @@ object HttpGo { ...@@ -82,7 +83,7 @@ object HttpGo {
/** /**
* 同步请求 * 同步请求
*/ */
inline fun <reified T> postSync(url: String, param: MutableMap<String, String>): BaseModel<T>? { inline fun <reified T> postSync(url: String, param: MutableMap<String, out Any>): BaseModel<T>? {
try { try {
val body: RequestBody = gson.toJson(param).toString().toRequestBody(jsonType) val body: RequestBody = gson.toJson(param).toString().toRequestBody(jsonType)
val request = Request.Builder() val request = Request.Builder()
......
...@@ -159,13 +159,12 @@ ...@@ -159,13 +159,12 @@
android:id="@+id/cb_protocol" android:id="@+id/cb_protocol"
android:padding="5dp" android:padding="5dp"
android:gravity="center" android:gravity="center"
android:layout_width="20dp" android:layout_width="25dp"
android:layout_height="20dp" android:layout_height="25dp"
style="@style/btn_checkbox" style="@style/btn_checkbox"
/> />
<TextView <TextView
android:layout_marginLeft="5dp"
style="@style/TextStyle.Explain" style="@style/TextStyle.Explain"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:text="您已阅读并同意" android:text="您已阅读并同意"
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="40.5dp"> android:layout_marginTop="47.5dp">
<TextView <TextView
android:id="@+id/acc_state_tx" android:id="@+id/acc_state_tx"
......
...@@ -6,6 +6,13 @@ ...@@ -6,6 +6,13 @@
android:background="@color/white" android:background="@color/white"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout
android:id="@+id/item_click_view"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<LinearLayout <LinearLayout
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
android:layout_marginRight="20dp" android:layout_marginRight="20dp"
...@@ -109,7 +116,7 @@ ...@@ -109,7 +116,7 @@
android:layout_height="182.5dp" android:layout_height="182.5dp"
android:layout_marginTop="12.65dp" android:layout_marginTop="12.65dp"
android:visibility="gone" /> android:visibility="gone" />
</LinearLayout>
<RelativeLayout <RelativeLayout
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
......
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/xg_root_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--通知的背景,id名字不能改变,其他可变-->
<ImageView
android:id="@+id/xg_notification_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<!--通知的大图标,id名字不能改变,其他可变.必须-->
<ImageView
android:id="@+id/xg_notification_icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:scaleType="centerInside" />
<!--通知的时间,id名字不能改变,其他可变.若不显示时间可以去掉此布局-->
<TextView
android:id="@+id/xg_notification_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:textSize="12dp" />
<!--通知的标题,id名字不能改变,其他可变。必须-->
<TextView
android:id="@+id/xg_notification_style_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="20dp"
android:layout_toLeftOf="@id/xg_notification_date"
android:layout_toRightOf="@id/xg_notification_icon"
android:singleLine="true" />
<!--通知的内容,id名字不能改变,其他可变。必须-->
<TextView
android:id="@+id/xg_notification_style_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/xg_notification_style_title"
android:layout_alignLeft="@+id/xg_notification_style_title"
android:layout_marginTop="1dp"
android:layout_toLeftOf="@id/xg_notification_date"
android:singleLine="true" />
<!--带音频的富媒体通知的音频播放按钮,id名字不能改变,其他可变。若没用到音频富媒体可以去掉此布局-->
<ImageView
android:id="@+id/xg_notification_audio_play"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignLeft="@+id/xg_notification_style_title"
android:layout_alignParentBottom="true"
android:background="@android:drawable/ic_media_play"
android:visibility="gone" />
<!--带音频的富媒体通知的音频停止播放按钮,id名字不能改变,其他可变.若没用到音频富媒体可以去掉此布局-->
<ImageView
android:id="@+id/xg_notification_audio_stop"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignParentBottom="true"
android:layout_marginLeft="30dp"
android:layout_toRightOf="@+id/xg_notification_audio_play"
android:background="@android:drawable/ic_media_pause"
android:visibility="gone" />
</RelativeLayout>
\ No newline at end of file
...@@ -105,10 +105,6 @@ ...@@ -105,10 +105,6 @@
android:theme="@style/Theme.Shadowsocks.ActionBar"/> android:theme="@style/Theme.Shadowsocks.ActionBar"/>
<activity android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity" <activity android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:theme="@style/Theme.Shadowsocks.ActionBar"/> android:theme="@style/Theme.Shadowsocks.ActionBar"/>
<service android:name="com.google.firebase.components.ComponentDiscoveryService"
android:directBootAware="true"/>
<provider android:name="com.google.firebase.provider.FirebaseInitProvider"
tools:node="remove"/>
<service android:name="androidx.room.MultiInstanceInvalidationService" <service android:name="androidx.room.MultiInstanceInvalidationService"
android:process=":bg"/> android:process=":bg"/>
</application> </application>
......
...@@ -39,18 +39,23 @@ import kotlin.concurrent.thread ...@@ -39,18 +39,23 @@ import kotlin.concurrent.thread
class GuardedProcessPool(private val onFatal: suspend (IOException) -> Unit) : CoroutineScope { class GuardedProcessPool(private val onFatal: suspend (IOException) -> Unit) : CoroutineScope {
companion object { companion object {
private val pid by lazy { private val pid by lazy {
Class.forName("java.lang.ProcessManager\$ProcessImpl").getDeclaredField("pid").apply { isAccessible = true } Class.forName("java.lang.ProcessManager\$ProcessImpl").getDeclaredField("pid")
.apply { isAccessible = true }
} }
} }
private inner class Guard(private val cmd: List<String>) { private inner class Guard(private val cmdSupplier: suspend () -> List<String>) {
private lateinit var process: Process private lateinit var process: Process
private lateinit var cmd: List<String>
private fun streamLogger(input: InputStream, logger: (String) -> Unit) = try { private fun streamLogger(input: InputStream, logger: (String) -> Unit) = try {
input.bufferedReader().forEachLine(logger) input.bufferedReader().forEachLine(logger)
} catch (_: IOException) { } // ignore } catch (_: IOException) {
} // ignore
fun start() { suspend fun start() {
cmd = cmdSupplier.invoke()
Timber.i("start process: ${Commandline.toString(cmd)}")
process = ProcessBuilder(cmd).directory(Core.deviceStorage.noBackupFilesDir).start() process = ProcessBuilder(cmd).directory(Core.deviceStorage.noBackupFilesDir).start()
} }
...@@ -74,7 +79,8 @@ class GuardedProcessPool(private val onFatal: suspend (IOException) -> Unit) : C ...@@ -74,7 +79,8 @@ class GuardedProcessPool(private val onFatal: suspend (IOException) -> Unit) : C
when { when {
exitCode == OsConstants.ECONNREFUSED -> throw IOException("connection refused by server") exitCode == OsConstants.ECONNREFUSED -> throw IOException("connection refused by server")
SystemClock.elapsedRealtime() - startTime < 1000 -> throw IOException( SystemClock.elapsedRealtime() - startTime < 1000 -> throw IOException(
"$cmdName exits too fast (exit code: $exitCode)") "$cmdName exits too fast (exit code: $exitCode)"
)
exitCode == 128 + OsConstants.SIGKILL -> Timber.w("$cmdName was killed") exitCode == 128 + OsConstants.SIGKILL -> Timber.w("$cmdName was killed")
else -> Timber.w(IOException("$cmdName unexpectedly exits with code $exitCode")) else -> Timber.w(IOException("$cmdName unexpectedly exits with code $exitCode"))
} }
...@@ -112,11 +118,15 @@ class GuardedProcessPool(private val onFatal: suspend (IOException) -> Unit) : C ...@@ -112,11 +118,15 @@ class GuardedProcessPool(private val onFatal: suspend (IOException) -> Unit) : C
override val coroutineContext = Dispatchers.Main.immediate + Job() override val coroutineContext = Dispatchers.Main.immediate + Job()
@MainThread @MainThread
fun start(cmd: List<String>, onRestartCallback: (suspend () -> Unit)? = null) { fun start(
Timber.i("start process: ${Commandline.toString(cmd)}") cmdSupplier: suspend () -> List<String>,
Guard(cmd).apply { onRestartCallback: (suspend () -> Unit)? = null
) {
Guard(cmdSupplier).apply {
launch {
start() // if start fails, IOException will be thrown directly start() // if start fails, IOException will be thrown directly
launch { looper(onRestartCallback) } looper(onRestartCallback)
}
} }
} }
......
...@@ -59,10 +59,11 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -59,10 +59,11 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
* Sensitive shadowsocks configuration file requires extra protection. It may be stored in encrypted storage or * Sensitive shadowsocks configuration file requires extra protection. It may be stored in encrypted storage or
* device storage, depending on which is currently available. * device storage, depending on which is currently available.
*/ */
fun start(service: BaseService.Interface, stat: File, configFile: File, mode: String, dnsRelay: Boolean = true) { suspend fun start(service: BaseService.Interface, stat: File, configFile: File, mode: String, dnsRelay: Boolean = true) {
// setup traffic monitor path // setup traffic monitor path
trafficMonitor = TrafficMonitor(stat) trafficMonitor = TrafficMonitor(stat)
val cmdSupplier: suspend () -> List<String> = {
AuthManager.initAuthProfile(profile)
// init JSON config // init JSON config
this.configFile = configFile this.configFile = configFile
val config = profile.toJson() val config = profile.toJson()
...@@ -100,6 +101,9 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -100,6 +101,9 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
}) })
} }
}) })
if (DataStore.outboundBindInterface.isNotBlank()) {
config.put("outbound-bind-interface", DataStore.outboundBindInterface)
}
configFile.writeText(config.toString()) configFile.writeText(config.toString())
Timber.d("prepare start service with config: $config") Timber.d("prepare start service with config: $config")
...@@ -116,6 +120,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -116,6 +120,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
if (route != Acl.ALL) { if (route != Acl.ALL) {
cmd += "--acl" cmd += "--acl"
cmd += Acl.getFile(route).absolutePath cmd += Acl.getFile(route).absolutePath
Timber.d("start vpn service with acl ${Acl.getFile(route).readText()}")
} }
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
...@@ -124,8 +129,10 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -124,8 +129,10 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
cmd += "-v" cmd += "-v"
cmd += "-v" cmd += "-v"
} }
cmd
}
service.data.processes!!.start(cmd) service.data.processes!!.start(cmdSupplier)
} }
fun scheduleUpdate() { fun scheduleUpdate() {
......
...@@ -224,7 +224,7 @@ class VpnService : BaseVpnService(), BaseService.Interface { ...@@ -224,7 +224,7 @@ class VpnService : BaseVpnService(), BaseService.Interface {
cmd += PRIVATE_VLAN6_ROUTER cmd += PRIVATE_VLAN6_ROUTER
} }
cmd += "--enable-udprelay" cmd += "--enable-udprelay"
data.processes!!.start(cmd, onRestartCallback = { data.processes!!.start(cmdSupplier = { cmd }, onRestartCallback = {
try { try {
sendFd(conn.fileDescriptor) sendFd(conn.fileDescriptor)
} catch (e: ErrnoException) { } catch (e: ErrnoException) {
......
...@@ -107,4 +107,7 @@ object DataStore : OnPreferenceDataStoreChangeListener { ...@@ -107,4 +107,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var dirty: Boolean var dirty: Boolean
get() = privateStore.getBoolean(Key.dirty) ?: false get() = privateStore.getBoolean(Key.dirty) ?: false
set(value) = privateStore.putBoolean(Key.dirty, value) set(value) = privateStore.putBoolean(Key.dirty, value)
var outboundBindInterface: String
get() = privateStore.getString(Key.outboundBindInterface) ?: ""
set(value) = privateStore.putString(Key.outboundBindInterface, value)
} }
...@@ -65,6 +65,7 @@ object Key { ...@@ -65,6 +65,7 @@ object Key {
const val plugin = "plugin" const val plugin = "plugin"
const val pluginConfigure = "plugin.configure" const val pluginConfigure = "plugin.configure"
const val udpFallback = "udpFallback" const val udpFallback = "udpFallback"
const val outboundBindInterface = "outboundBindInterface"
const val dirty = "profileDirty" const val dirty = "profileDirty"
......
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