From 8418155826cd5583037ea015f7efbd8829884f77 Mon Sep 17 00:00:00 2001 From: pppscn <35696959@qq.com> Date: Wed, 21 Sep 2022 09:48:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E5=9C=B0=E5=9D=80=E6=97=B6=EF=BC=8C?= =?UTF-8?q?IPv6=E5=9C=B0=E5=9D=80=E5=8A=A0[]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sms/forwarder/fragment/ServerFragment.kt | 683 +++++++++--------- 1 file changed, 342 insertions(+), 341 deletions(-) diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt index 3491ce5a..231897f8 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt @@ -1,342 +1,343 @@ -package com.idormy.sms.forwarder.fragment - -import android.content.Intent -import android.os.Environment -import android.os.Handler -import android.os.Looper -import android.text.Editable -import android.text.TextWatcher -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.CompoundButton -import com.hjq.permissions.OnPermissionCallback -import com.hjq.permissions.Permission -import com.hjq.permissions.XXPermissions -import com.idormy.sms.forwarder.App -import com.idormy.sms.forwarder.R -import com.idormy.sms.forwarder.core.BaseFragment -import com.idormy.sms.forwarder.databinding.FragmentServerBinding -import com.idormy.sms.forwarder.service.HttpService -import com.idormy.sms.forwarder.utils.HTTP_SERVER_PORT -import com.idormy.sms.forwarder.utils.HttpServerUtils -import com.idormy.sms.forwarder.utils.RandomUtils -import com.idormy.sms.forwarder.utils.XToastUtils -import com.xuexiang.xaop.annotation.SingleClick -import com.xuexiang.xpage.annotation.Page -import com.xuexiang.xui.widget.actionbar.TitleBar -import com.xuexiang.xui.widget.button.SmoothCheckBox -import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog -import com.xuexiang.xutil.app.ServiceUtils -import com.xuexiang.xutil.net.NetworkUtils -import com.xuexiang.xutil.system.ClipboardUtils -import java.io.File -import java.net.InetAddress - - -@Suppress("PrivatePropertyName") -@Page(name = "主动控制·服务端") -class ServerFragment : BaseFragment(), View.OnClickListener { - - private var appContext: App? = null - private var inetAddress: InetAddress? = null - - //定时更新界面 - private val handler: Handler = Handler(Looper.getMainLooper()) - private val runnable: Runnable = object : Runnable { - override fun run() { - handler.postDelayed(this, 1000) //每隔1秒刷新一次 - refreshButtonText() - } - } - - override fun initViews() { - appContext = requireActivity().application as App - } - - override fun initTitle(): TitleBar? { - val titleBar = super.initTitle()!!.setImmersive(false) - titleBar.setTitle(R.string.menu_server) - return titleBar - } - - override fun viewBindingInflate( - inflater: LayoutInflater, - container: ViewGroup, - ): FragmentServerBinding { - return FragmentServerBinding.inflate(inflater, container, false) - } - - override fun initListeners() { - binding!!.tvServerTips.setOnClickListener(this) - binding!!.ivCopy.setOnClickListener(this) - binding!!.btnToggleServer.setOnClickListener(this) - - binding!!.scbServerAutorun.isChecked = HttpServerUtils.enableServerAutorun - binding!!.scbServerAutorun.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean -> - HttpServerUtils.enableServerAutorun = isChecked - } - //启动更新UI定时器 - handler.post(runnable) - - binding!!.btnSignKey.setOnClickListener(this) - binding!!.btnPathPicker.setOnClickListener(this) - binding!!.etSignKey.setText(HttpServerUtils.serverSignKey) - binding!!.etSignKey.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} - override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} - override fun afterTextChanged(s: Editable) { - HttpServerUtils.serverSignKey = binding!!.etSignKey.text.toString().trim() - } - }) - binding!!.etWebPath.setText(HttpServerUtils.serverWebPath) - binding!!.etWebPath.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} - override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} - override fun afterTextChanged(s: Editable) { - HttpServerUtils.serverWebPath = binding!!.etWebPath.text.toString().trim() - } - }) - - binding!!.sbApiClone.isChecked = HttpServerUtils.enableApiClone - binding!!.sbApiClone.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> - HttpServerUtils.enableApiClone = isChecked - } - - binding!!.sbApiSendSms.isChecked = HttpServerUtils.enableApiSmsSend - binding!!.sbApiSendSms.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> - HttpServerUtils.enableApiSmsSend = isChecked - if (isChecked) checkSendSmsPermission() - } - - binding!!.sbApiQuerySms.isChecked = HttpServerUtils.enableApiSmsQuery - binding!!.sbApiQuerySms.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> - HttpServerUtils.enableApiSmsQuery = isChecked - if (isChecked) checkReadSmsPermission() - } - - binding!!.sbApiQueryCall.isChecked = HttpServerUtils.enableApiCallQuery - binding!!.sbApiQueryCall.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> - HttpServerUtils.enableApiCallQuery = isChecked - if (isChecked) checkCallPermission() - } - - binding!!.sbApiQueryContacts.isChecked = HttpServerUtils.enableApiContactQuery - binding!!.sbApiQueryContacts.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> - HttpServerUtils.enableApiContactQuery = isChecked - if (isChecked) checkContactsPermission() - } - - binding!!.sbApiQueryBattery.isChecked = HttpServerUtils.enableApiBatteryQuery - binding!!.sbApiQueryBattery.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> - HttpServerUtils.enableApiBatteryQuery = isChecked - } - - binding!!.sbApiWol.isChecked = HttpServerUtils.enableApiWol - binding!!.sbApiWol.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> - HttpServerUtils.enableApiWol = isChecked - } - - } - - @SingleClick - override fun onClick(v: View) { - when (v.id) { - R.id.btn_toggle_server -> { - //检查权限是否获取 - checkSendSmsPermission() - checkReadSmsPermission() - checkCallPermission() - checkContactsPermission() - if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) { - appContext?.stopService(Intent(appContext, HttpService::class.java)) - } else { - appContext?.startService(Intent(appContext, HttpService::class.java)) - } - refreshButtonText() - } - R.id.btn_sign_key -> { - val sign = RandomUtils.getRandomNumbersAndLetters(16) - ClipboardUtils.copyText(sign) - binding!!.etSignKey.setText(sign) - XToastUtils.info(getString(R.string.sign_key_tips)) - } - R.id.tv_server_tips, R.id.iv_copy -> { - val url = if (inetAddress != null) "http://${inetAddress?.hostAddress}:5000" else "http://127.0.0.1:5000" - ClipboardUtils.copyText(url) - XToastUtils.info(String.format(getString(R.string.copied_to_clipboard), url)) - } - R.id.btn_path_picker -> { - val downloadPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path - val dirList = listSubDir(downloadPath) - if (dirList.isEmpty()) { - XToastUtils.error(String.format(getString(R.string.download_first), downloadPath)) - return - } - MaterialDialog.Builder(requireContext()) - .title(getString(R.string.select_web_client_directory)) - .content(String.format(getString(R.string.root_directory), downloadPath)) - .items(dirList) - .itemsCallbackSingleChoice(0) { _: MaterialDialog?, _: View?, _: Int, text: CharSequence -> - val webPath = "$downloadPath/$text" - binding!!.etWebPath.setText(webPath) - HttpServerUtils.serverWebPath = webPath - - XToastUtils.info(getString(R.string.restarting_httpserver)) - if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) { - appContext?.stopService(Intent(appContext, HttpService::class.java)) - appContext?.startService(Intent(appContext, HttpService::class.java)) - } else { - appContext?.startService(Intent(appContext, HttpService::class.java)) - } - refreshButtonText() - true // allow selection - } - .positiveText(R.string.select) - .negativeText(R.string.cancel) - .show() - } - else -> {} - } - } - - //刷新按钮 - private fun refreshButtonText() { - if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) { - binding!!.btnToggleServer.text = resources.getText(R.string.stop_server) - binding!!.ivCopy.visibility = View.VISIBLE - try { - inetAddress = NetworkUtils.getLocalInetAddress() - binding!!.tvServerTips.text = getString(R.string.http_server_running, inetAddress!!.hostAddress, HTTP_SERVER_PORT) - - } catch (e: Exception) { - e.printStackTrace() - binding!!.tvServerTips.text = getString(R.string.http_server_running, "127.0.0.1", HTTP_SERVER_PORT) - } - } else { - binding!!.btnToggleServer.text = resources.getText(R.string.start_server) - binding!!.tvServerTips.text = getString(R.string.http_server_stopped) - binding!!.ivCopy.visibility = View.GONE - } - } - - //发送短信权限 - private fun checkSendSmsPermission() { - XXPermissions.with(this) - // 发送短信 - .permission(Permission.SEND_SMS) - .request(object : OnPermissionCallback { - override fun onGranted(permissions: List, all: Boolean) { - } - - override fun onDenied(permissions: List, never: Boolean) { - if (never) { - XToastUtils.error(R.string.toast_denied_never) - // 如果是被永久拒绝就跳转到应用权限系统设置页面 - XXPermissions.startPermissionActivity(requireContext(), permissions) - } else { - XToastUtils.error(R.string.toast_denied) - } - HttpServerUtils.enableApiSmsSend = false - binding!!.sbApiSendSms.isChecked = false - } - }) - } - - //读取短信权限 - private fun checkReadSmsPermission() { - XXPermissions.with(this) - // 接收短信 - .permission(Permission.RECEIVE_SMS) - // 发送短信 - .permission(Permission.SEND_SMS) - // 读取短信 - .permission(Permission.READ_SMS) - .request(object : OnPermissionCallback { - override fun onGranted(permissions: List, all: Boolean) { - } - - override fun onDenied(permissions: List, never: Boolean) { - if (never) { - XToastUtils.error(R.string.toast_denied_never) - // 如果是被永久拒绝就跳转到应用权限系统设置页面 - XXPermissions.startPermissionActivity(requireContext(), permissions) - } else { - XToastUtils.error(R.string.toast_denied) - } - HttpServerUtils.enableApiSmsQuery = false - binding!!.sbApiQuerySms.isChecked = false - } - }) - } - - //电话权限 - private fun checkCallPermission() { - XXPermissions.with(this) - // 读取电话状态 - .permission(Permission.READ_PHONE_STATE) - // 读取手机号码 - .permission(Permission.READ_PHONE_NUMBERS) - // 读取通话记录 - .permission(Permission.READ_CALL_LOG) - .request(object : OnPermissionCallback { - override fun onGranted(permissions: List, all: Boolean) { - } - - override fun onDenied(permissions: List, never: Boolean) { - if (never) { - XToastUtils.error(R.string.toast_denied_never) - // 如果是被永久拒绝就跳转到应用权限系统设置页面 - XXPermissions.startPermissionActivity(requireContext(), permissions) - } else { - XToastUtils.error(R.string.toast_denied) - } - HttpServerUtils.enableApiCallQuery = false - binding!!.sbApiQueryCall.isChecked = false - } - }) - } - - //联系人权限 - private fun checkContactsPermission() { - XXPermissions.with(this) - .permission(*Permission.Group.CONTACTS) - .request(object : OnPermissionCallback { - override fun onGranted(permissions: List, all: Boolean) { - } - - override fun onDenied(permissions: List, never: Boolean) { - if (never) { - XToastUtils.error(R.string.toast_denied_never) - // 如果是被永久拒绝就跳转到应用权限系统设置页面 - XXPermissions.startPermissionActivity(requireContext(), permissions) - } else { - XToastUtils.error(R.string.toast_denied) - } - HttpServerUtils.enableApiContactQuery = false - binding!!.sbApiQueryContacts.isChecked = false - } - }) - } - - override fun onDestroy() { - super.onDestroy() - //取消定时器 - handler.removeCallbacks(runnable) - } - - //获取Download的子目录 - private fun listSubDir(downloadPath: String): List { - val dirList = mutableListOf() - val downloadDir = File(downloadPath) - val files = downloadDir.listFiles() ?: return dirList - - for (file in files) { - if (file.isDirectory && !file.name.startsWith(".") && !file.name.startsWith("leakcanary-")) { - dirList.add(file.name) - } - } - return dirList - } - +package com.idormy.sms.forwarder.fragment + +import android.content.Intent +import android.os.Environment +import android.os.Handler +import android.os.Looper +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.CompoundButton +import com.hjq.permissions.OnPermissionCallback +import com.hjq.permissions.Permission +import com.hjq.permissions.XXPermissions +import com.idormy.sms.forwarder.App +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.core.BaseFragment +import com.idormy.sms.forwarder.databinding.FragmentServerBinding +import com.idormy.sms.forwarder.service.HttpService +import com.idormy.sms.forwarder.utils.HTTP_SERVER_PORT +import com.idormy.sms.forwarder.utils.HttpServerUtils +import com.idormy.sms.forwarder.utils.RandomUtils +import com.idormy.sms.forwarder.utils.XToastUtils +import com.xuexiang.xaop.annotation.SingleClick +import com.xuexiang.xpage.annotation.Page +import com.xuexiang.xui.widget.actionbar.TitleBar +import com.xuexiang.xui.widget.button.SmoothCheckBox +import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog +import com.xuexiang.xutil.app.ServiceUtils +import com.xuexiang.xutil.net.NetworkUtils +import com.xuexiang.xutil.system.ClipboardUtils +import java.io.File +import java.net.InetAddress + + +@Suppress("PrivatePropertyName") +@Page(name = "主动控制·服务端") +class ServerFragment : BaseFragment(), View.OnClickListener { + + private var appContext: App? = null + private var inetAddress: InetAddress? = null + + //定时更新界面 + private val handler: Handler = Handler(Looper.getMainLooper()) + private val runnable: Runnable = object : Runnable { + override fun run() { + handler.postDelayed(this, 1000) //每隔1秒刷新一次 + refreshButtonText() + } + } + + override fun initViews() { + appContext = requireActivity().application as App + } + + override fun initTitle(): TitleBar? { + val titleBar = super.initTitle()!!.setImmersive(false) + titleBar.setTitle(R.string.menu_server) + return titleBar + } + + override fun viewBindingInflate( + inflater: LayoutInflater, + container: ViewGroup, + ): FragmentServerBinding { + return FragmentServerBinding.inflate(inflater, container, false) + } + + override fun initListeners() { + binding!!.tvServerTips.setOnClickListener(this) + binding!!.ivCopy.setOnClickListener(this) + binding!!.btnToggleServer.setOnClickListener(this) + + binding!!.scbServerAutorun.isChecked = HttpServerUtils.enableServerAutorun + binding!!.scbServerAutorun.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean -> + HttpServerUtils.enableServerAutorun = isChecked + } + //启动更新UI定时器 + handler.post(runnable) + + binding!!.btnSignKey.setOnClickListener(this) + binding!!.btnPathPicker.setOnClickListener(this) + binding!!.etSignKey.setText(HttpServerUtils.serverSignKey) + binding!!.etSignKey.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} + override fun afterTextChanged(s: Editable) { + HttpServerUtils.serverSignKey = binding!!.etSignKey.text.toString().trim() + } + }) + binding!!.etWebPath.setText(HttpServerUtils.serverWebPath) + binding!!.etWebPath.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} + override fun afterTextChanged(s: Editable) { + HttpServerUtils.serverWebPath = binding!!.etWebPath.text.toString().trim() + } + }) + + binding!!.sbApiClone.isChecked = HttpServerUtils.enableApiClone + binding!!.sbApiClone.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> + HttpServerUtils.enableApiClone = isChecked + } + + binding!!.sbApiSendSms.isChecked = HttpServerUtils.enableApiSmsSend + binding!!.sbApiSendSms.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> + HttpServerUtils.enableApiSmsSend = isChecked + if (isChecked) checkSendSmsPermission() + } + + binding!!.sbApiQuerySms.isChecked = HttpServerUtils.enableApiSmsQuery + binding!!.sbApiQuerySms.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> + HttpServerUtils.enableApiSmsQuery = isChecked + if (isChecked) checkReadSmsPermission() + } + + binding!!.sbApiQueryCall.isChecked = HttpServerUtils.enableApiCallQuery + binding!!.sbApiQueryCall.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> + HttpServerUtils.enableApiCallQuery = isChecked + if (isChecked) checkCallPermission() + } + + binding!!.sbApiQueryContacts.isChecked = HttpServerUtils.enableApiContactQuery + binding!!.sbApiQueryContacts.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> + HttpServerUtils.enableApiContactQuery = isChecked + if (isChecked) checkContactsPermission() + } + + binding!!.sbApiQueryBattery.isChecked = HttpServerUtils.enableApiBatteryQuery + binding!!.sbApiQueryBattery.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> + HttpServerUtils.enableApiBatteryQuery = isChecked + } + + binding!!.sbApiWol.isChecked = HttpServerUtils.enableApiWol + binding!!.sbApiWol.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> + HttpServerUtils.enableApiWol = isChecked + } + + } + + @SingleClick + override fun onClick(v: View) { + when (v.id) { + R.id.btn_toggle_server -> { + //检查权限是否获取 + checkSendSmsPermission() + checkReadSmsPermission() + checkCallPermission() + checkContactsPermission() + if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) { + appContext?.stopService(Intent(appContext, HttpService::class.java)) + } else { + appContext?.startService(Intent(appContext, HttpService::class.java)) + } + refreshButtonText() + } + R.id.btn_sign_key -> { + val sign = RandomUtils.getRandomNumbersAndLetters(16) + ClipboardUtils.copyText(sign) + binding!!.etSignKey.setText(sign) + XToastUtils.info(getString(R.string.sign_key_tips)) + } + R.id.tv_server_tips, R.id.iv_copy -> { + var hostAddress: String = if (inetAddress != null) "${inetAddress?.hostAddress}" else "127.0.0.1" + hostAddress = if (hostAddress.indexOf(':', 0, false) > 0) "[${hostAddress}]" else hostAddress + val url = "http://${hostAddress}:5000" + ClipboardUtils.copyText(url) + XToastUtils.info(String.format(getString(R.string.copied_to_clipboard), url)) + } + R.id.btn_path_picker -> { + val downloadPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path + val dirList = listSubDir(downloadPath) + if (dirList.isEmpty()) { + XToastUtils.error(String.format(getString(R.string.download_first), downloadPath)) + return + } + MaterialDialog.Builder(requireContext()) + .title(getString(R.string.select_web_client_directory)) + .content(String.format(getString(R.string.root_directory), downloadPath)) + .items(dirList) + .itemsCallbackSingleChoice(0) { _: MaterialDialog?, _: View?, _: Int, text: CharSequence -> + val webPath = "$downloadPath/$text" + binding!!.etWebPath.setText(webPath) + HttpServerUtils.serverWebPath = webPath + + XToastUtils.info(getString(R.string.restarting_httpserver)) + if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) { + appContext?.stopService(Intent(appContext, HttpService::class.java)) + appContext?.startService(Intent(appContext, HttpService::class.java)) + } else { + appContext?.startService(Intent(appContext, HttpService::class.java)) + } + refreshButtonText() + true // allow selection + } + .positiveText(R.string.select) + .negativeText(R.string.cancel) + .show() + } + else -> {} + } + } + + //刷新按钮 + private fun refreshButtonText() { + if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) { + binding!!.btnToggleServer.text = resources.getText(R.string.stop_server) + binding!!.ivCopy.visibility = View.VISIBLE + try { + inetAddress = NetworkUtils.getLocalInetAddress() + binding!!.tvServerTips.text = getString(R.string.http_server_running, inetAddress!!.hostAddress, HTTP_SERVER_PORT) + } catch (e: Exception) { + e.printStackTrace() + binding!!.tvServerTips.text = getString(R.string.http_server_running, "127.0.0.1", HTTP_SERVER_PORT) + } + } else { + binding!!.btnToggleServer.text = resources.getText(R.string.start_server) + binding!!.tvServerTips.text = getString(R.string.http_server_stopped) + binding!!.ivCopy.visibility = View.GONE + } + } + + //发送短信权限 + private fun checkSendSmsPermission() { + XXPermissions.with(this) + // 发送短信 + .permission(Permission.SEND_SMS) + .request(object : OnPermissionCallback { + override fun onGranted(permissions: List, all: Boolean) { + } + + override fun onDenied(permissions: List, never: Boolean) { + if (never) { + XToastUtils.error(R.string.toast_denied_never) + // 如果是被永久拒绝就跳转到应用权限系统设置页面 + XXPermissions.startPermissionActivity(requireContext(), permissions) + } else { + XToastUtils.error(R.string.toast_denied) + } + HttpServerUtils.enableApiSmsSend = false + binding!!.sbApiSendSms.isChecked = false + } + }) + } + + //读取短信权限 + private fun checkReadSmsPermission() { + XXPermissions.with(this) + // 接收短信 + .permission(Permission.RECEIVE_SMS) + // 发送短信 + .permission(Permission.SEND_SMS) + // 读取短信 + .permission(Permission.READ_SMS) + .request(object : OnPermissionCallback { + override fun onGranted(permissions: List, all: Boolean) { + } + + override fun onDenied(permissions: List, never: Boolean) { + if (never) { + XToastUtils.error(R.string.toast_denied_never) + // 如果是被永久拒绝就跳转到应用权限系统设置页面 + XXPermissions.startPermissionActivity(requireContext(), permissions) + } else { + XToastUtils.error(R.string.toast_denied) + } + HttpServerUtils.enableApiSmsQuery = false + binding!!.sbApiQuerySms.isChecked = false + } + }) + } + + //电话权限 + private fun checkCallPermission() { + XXPermissions.with(this) + // 读取电话状态 + .permission(Permission.READ_PHONE_STATE) + // 读取手机号码 + .permission(Permission.READ_PHONE_NUMBERS) + // 读取通话记录 + .permission(Permission.READ_CALL_LOG) + .request(object : OnPermissionCallback { + override fun onGranted(permissions: List, all: Boolean) { + } + + override fun onDenied(permissions: List, never: Boolean) { + if (never) { + XToastUtils.error(R.string.toast_denied_never) + // 如果是被永久拒绝就跳转到应用权限系统设置页面 + XXPermissions.startPermissionActivity(requireContext(), permissions) + } else { + XToastUtils.error(R.string.toast_denied) + } + HttpServerUtils.enableApiCallQuery = false + binding!!.sbApiQueryCall.isChecked = false + } + }) + } + + //联系人权限 + private fun checkContactsPermission() { + XXPermissions.with(this) + .permission(*Permission.Group.CONTACTS) + .request(object : OnPermissionCallback { + override fun onGranted(permissions: List, all: Boolean) { + } + + override fun onDenied(permissions: List, never: Boolean) { + if (never) { + XToastUtils.error(R.string.toast_denied_never) + // 如果是被永久拒绝就跳转到应用权限系统设置页面 + XXPermissions.startPermissionActivity(requireContext(), permissions) + } else { + XToastUtils.error(R.string.toast_denied) + } + HttpServerUtils.enableApiContactQuery = false + binding!!.sbApiQueryContacts.isChecked = false + } + }) + } + + override fun onDestroy() { + super.onDestroy() + //取消定时器 + handler.removeCallbacks(runnable) + } + + //获取Download的子目录 + private fun listSubDir(downloadPath: String): List { + val dirList = mutableListOf() + val downloadDir = File(downloadPath) + val files = downloadDir.listFiles() ?: return dirList + + for (file in files) { + if (file.isDirectory && !file.name.startsWith(".") && !file.name.startsWith("leakcanary-")) { + dirList.add(file.name) + } + } + return dirList + } + } \ No newline at end of file