新增:远程改话簿(方便给老人家添加联系人) #256

pull/286/head
pppscn 1 year ago
parent f9ddbd7261
commit 1e1dd8e3fd

@ -259,7 +259,7 @@ class ClientFragment : BaseFragment<FragmentClientBinding?>(), View.OnClickListe
XToastUtils.error(getString(R.string.click_test_button_first))
return
}
if (serverConfig != null && ((item.name == ResUtils.getString(R.string.api_sms_send) && !serverConfig!!.enableApiSmsSend) || (item.name == ResUtils.getString(R.string.api_sms_query) && !serverConfig!!.enableApiSmsQuery) || (item.name == ResUtils.getString(R.string.api_call_query) && !serverConfig!!.enableApiCallQuery) || (item.name == ResUtils.getString(R.string.api_contact_query) && !serverConfig!!.enableApiContactQuery) || (item.name == ResUtils.getString(R.string.api_battery_query) && !serverConfig!!.enableApiBatteryQuery) || (item.name == ResUtils.getString(R.string.api_wol) && !serverConfig!!.enableApiWol) || (item.name == ResUtils.getString(R.string.api_location) && !serverConfig!!.enableApiLocation))) {
if (serverConfig != null && ((item.name == ResUtils.getString(R.string.api_sms_send) && !serverConfig!!.enableApiSmsSend) || (item.name == ResUtils.getString(R.string.api_sms_query) && !serverConfig!!.enableApiSmsQuery) || (item.name == ResUtils.getString(R.string.api_call_query) && !serverConfig!!.enableApiCallQuery) || (item.name == ResUtils.getString(R.string.api_contact_query) && !serverConfig!!.enableApiContactQuery) || (item.name == ResUtils.getString(R.string.api_contact_add) && !serverConfig!!.enableApiContactAdd) || (item.name == ResUtils.getString(R.string.api_battery_query) && !serverConfig!!.enableApiBatteryQuery) || (item.name == ResUtils.getString(R.string.api_wol) && !serverConfig!!.enableApiWol) || (item.name == ResUtils.getString(R.string.api_location) && !serverConfig!!.enableApiLocation))) {
XToastUtils.error(getString(R.string.disabled_on_the_server))
return
}

@ -215,6 +215,12 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
if (isChecked) checkContactsPermission()
}
binding!!.sbApiAddContacts.isChecked = HttpServerUtils.enableApiContactAdd
binding!!.sbApiAddContacts.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
HttpServerUtils.enableApiContactAdd = isChecked
if (isChecked) checkContactsPermission()
}
binding!!.sbApiQueryBattery.isChecked = HttpServerUtils.enableApiBatteryQuery
binding!!.sbApiQueryBattery.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
HttpServerUtils.enableApiBatteryQuery = isChecked
@ -435,6 +441,8 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
}
HttpServerUtils.enableApiContactQuery = false
binding!!.sbApiQueryContacts.isChecked = false
HttpServerUtils.enableApiContactAdd = false
binding!!.sbApiAddContacts.isChecked = false
}
})
}

@ -0,0 +1,186 @@
package com.idormy.sms.forwarder.fragment.client
import android.annotation.SuppressLint
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.databinding.FragmentClientContactAddBinding
import com.idormy.sms.forwarder.server.model.BaseResponse
import com.idormy.sms.forwarder.utils.*
import com.jeremyliao.liveeventbus.LiveEventBus
import com.xuexiang.xaop.annotation.SingleClick
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.cache.model.CacheMode
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
import com.xuexiang.xpage.annotation.Page
import com.xuexiang.xrouter.utils.TextUtils
import com.xuexiang.xui.utils.CountDownButtonHelper
import com.xuexiang.xui.utils.ResUtils
import com.xuexiang.xui.widget.actionbar.TitleBar
import com.xuexiang.xutil.data.ConvertTools
@Suppress("PropertyName")
@Page(name = "远程加话簿")
class ContactAddFragment : BaseFragment<FragmentClientContactAddBinding?>(), View.OnClickListener {
val TAG: String = ContactAddFragment::class.java.simpleName
private var mCountDownHelper: CountDownButtonHelper? = null
override fun viewBindingInflate(
inflater: LayoutInflater,
container: ViewGroup,
): FragmentClientContactAddBinding {
return FragmentClientContactAddBinding.inflate(inflater, container, false)
}
override fun initTitle(): TitleBar? {
return super.initTitle()!!.setImmersive(false).setTitle(R.string.api_contact_add)
}
/**
* 初始化控件
*/
@SuppressLint("SetTextI18n")
override fun initViews() {
//发送按钮增加倒计时,避免重复点击
mCountDownHelper = CountDownButtonHelper(binding!!.btnSubmit, SettingUtils.requestTimeout)
mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener {
override fun onCountDown(time: Int) {
binding!!.btnSubmit.text = String.format(getString(R.string.seconds_n), time)
}
override fun onFinished() {
binding!!.btnSubmit.text = getString(R.string.submit)
}
})
}
override fun initListeners() {
binding!!.btnSubmit.setOnClickListener(this)
LiveEventBus.get(EVENT_KEY_PHONE_NUMBERS, String::class.java).observeSticky(this) { value: String ->
binding!!.etPhoneNumbers.setText(value)
}
}
@SingleClick
override fun onClick(v: View) {
when (v.id) {
R.id.btn_submit -> {
val requestUrl: String = HttpServerUtils.serverAddress + "/contact/add"
Log.i(TAG, "requestUrl:$requestUrl")
val msgMap: MutableMap<String, Any> = mutableMapOf()
val timestamp = System.currentTimeMillis()
msgMap["timestamp"] = timestamp
val clientSignKey = HttpServerUtils.clientSignKey
if (!TextUtils.isEmpty(clientSignKey)) {
msgMap["sign"] = HttpServerUtils.calcSign(timestamp.toString(), clientSignKey)
}
val phoneNumbers = binding!!.etPhoneNumbers.text.toString()
val phoneRegex = getString(R.string.phone_numbers_regex).toRegex()
if (!phoneRegex.matches(phoneNumbers)) {
XToastUtils.error(ResUtils.getString(R.string.phone_numbers_error))
return
}
val name = binding!!.etDisplayName.text.toString()
val dataMap: MutableMap<String, Any> = mutableMapOf()
dataMap["phone_number"] = phoneNumbers
dataMap["name"] = name
msgMap["data"] = dataMap
var requestMsg: String = Gson().toJson(msgMap)
Log.i(TAG, "requestMsg:$requestMsg")
val postRequest = XHttp.post(requestUrl)
.keepJson(true)
.timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s
.cacheMode(CacheMode.NO_CACHE)
.timeStamp(true)
when (HttpServerUtils.clientSafetyMeasures) {
2 -> {
val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey)
try {
requestMsg = Base64.encode(requestMsg.toByteArray())
requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey)
Log.i(TAG, "requestMsg: $requestMsg")
} catch (e: Exception) {
XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message)
e.printStackTrace()
return
}
postRequest.upString(requestMsg)
}
3 -> {
try {
val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey)
//requestMsg = Base64.encode(requestMsg.toByteArray())
val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key)
requestMsg = ConvertTools.bytes2HexString(encryptCBC)
Log.i(TAG, "requestMsg: $requestMsg")
} catch (e: Exception) {
XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message)
e.printStackTrace()
return
}
postRequest.upString(requestMsg)
}
else -> {
postRequest.upJson(requestMsg)
}
}
mCountDownHelper?.start()
postRequest.execute(object : SimpleCallBack<String>() {
override fun onError(e: ApiException) {
XToastUtils.error(e.displayMessage)
mCountDownHelper?.finish()
}
override fun onSuccess(response: String) {
Log.i(TAG, response)
try {
var json = response
if (HttpServerUtils.clientSafetyMeasures == 2) {
val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey)
json = RSACrypt.decryptByPublicKey(json, publicKey)
json = String(Base64.decode(json))
} else if (HttpServerUtils.clientSafetyMeasures == 3) {
val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey)
val encryptCBC = ConvertTools.hexStringToByteArray(json)
val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key)
json = String(decryptCBC)
}
val resp: BaseResponse<String> = Gson().fromJson(json, object : TypeToken<BaseResponse<String>>() {}.type)
if (resp.code == 200) {
XToastUtils.success(ResUtils.getString(R.string.request_succeeded))
} else {
XToastUtils.error(ResUtils.getString(R.string.request_failed) + resp.msg)
}
} catch (e: Exception) {
e.printStackTrace()
XToastUtils.error(ResUtils.getString(R.string.request_failed) + response)
}
mCountDownHelper?.finish()
}
})
}
else -> {}
}
}
override fun onDestroyView() {
if (mCountDownHelper != null) mCountDownHelper!!.recycle()
super.onDestroyView()
}
}

@ -1,55 +1,58 @@
package com.idormy.sms.forwarder.server.component
import android.util.Log
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.utils.HttpServerUtils
import com.xuexiang.xui.utils.ResUtils.getString
import com.yanzhenjie.andserver.annotation.Interceptor
import com.yanzhenjie.andserver.error.HttpException
import com.yanzhenjie.andserver.framework.HandlerInterceptor
import com.yanzhenjie.andserver.framework.handler.MethodHandler
import com.yanzhenjie.andserver.framework.handler.RequestHandler
import com.yanzhenjie.andserver.http.HttpMethod
import com.yanzhenjie.andserver.http.HttpRequest
import com.yanzhenjie.andserver.http.HttpResponse
@Suppress("PrivatePropertyName")
@Interceptor
class LoggerInterceptor : HandlerInterceptor {
private val TAG: String = "LoggerInterceptor"
override fun onIntercept(
request: HttpRequest,
respons: HttpResponse,
handler: RequestHandler,
): Boolean {
if (handler is MethodHandler) {
val httpPath = request.path
val method: HttpMethod = request.method
val valueMap = request.parameter
Log.i(TAG, "Path: $httpPath")
Log.i(TAG, "Method: " + method.value())
Log.i(TAG, "Param: $valueMap")
//判断是否开启该功能
if (
(httpPath.startsWith("/clone") && !HttpServerUtils.enableApiClone)
|| (httpPath.startsWith("/sms/send") && !HttpServerUtils.enableApiSmsSend)
|| (httpPath.startsWith("/sms/query") && !HttpServerUtils.enableApiSmsQuery)
|| (httpPath.startsWith("/call/query") && !HttpServerUtils.enableApiCallQuery)
|| (httpPath.startsWith("/contact/query") && !HttpServerUtils.enableApiContactQuery)
|| (httpPath.startsWith("/battery/query") && !HttpServerUtils.enableApiBatteryQuery)
) {
throw HttpException(500, getString(R.string.disabled_on_the_server))
}
/*
//注意这里读取body会导致 MessageConverter 报错RequestBody is missing.
val body = request.body?.string()
Log.i(TAG, "Body: $body")
*/
}
return false
}
package com.idormy.sms.forwarder.server.component
import android.util.Log
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.utils.HttpServerUtils
import com.xuexiang.xui.utils.ResUtils.getString
import com.yanzhenjie.andserver.annotation.Interceptor
import com.yanzhenjie.andserver.error.HttpException
import com.yanzhenjie.andserver.framework.HandlerInterceptor
import com.yanzhenjie.andserver.framework.handler.MethodHandler
import com.yanzhenjie.andserver.framework.handler.RequestHandler
import com.yanzhenjie.andserver.http.HttpMethod
import com.yanzhenjie.andserver.http.HttpRequest
import com.yanzhenjie.andserver.http.HttpResponse
@Suppress("PrivatePropertyName")
@Interceptor
class LoggerInterceptor : HandlerInterceptor {
private val TAG: String = "LoggerInterceptor"
override fun onIntercept(
request: HttpRequest,
respons: HttpResponse,
handler: RequestHandler,
): Boolean {
if (handler is MethodHandler) {
val httpPath = request.path
val method: HttpMethod = request.method
val valueMap = request.parameter
Log.i(TAG, "Path: $httpPath")
Log.i(TAG, "Method: " + method.value())
Log.i(TAG, "Param: $valueMap")
//判断是否开启该功能
if (
(httpPath.startsWith("/clone") && !HttpServerUtils.enableApiClone)
|| (httpPath.startsWith("/sms/query") && !HttpServerUtils.enableApiSmsQuery)
|| (httpPath.startsWith("/sms/send") && !HttpServerUtils.enableApiSmsSend)
|| (httpPath.startsWith("/call/query") && !HttpServerUtils.enableApiCallQuery)
|| (httpPath.startsWith("/contact/query") && !HttpServerUtils.enableApiContactQuery)
|| (httpPath.startsWith("/contact/add") && !HttpServerUtils.enableApiContactAdd)
|| (httpPath.startsWith("/wol/send") && !HttpServerUtils.enableApiWol)
|| (httpPath.startsWith("/location/query") && !HttpServerUtils.enableApiLocation)
|| (httpPath.startsWith("/battery/query") && !HttpServerUtils.enableApiBatteryQuery)
) {
throw HttpException(500, getString(R.string.disabled_on_the_server))
}
/*
//注意这里读取body会导致 MessageConverter 报错RequestBody is missing.
val body = request.body?.string()
Log.i(TAG, "Body: $body")
*/
}
return false
}
}

@ -35,6 +35,7 @@ class ConfigController {
HttpServerUtils.enableApiSmsQuery,
HttpServerUtils.enableApiCallQuery,
HttpServerUtils.enableApiContactQuery,
HttpServerUtils.enableApiContactAdd,
HttpServerUtils.enableApiBatteryQuery,
HttpServerUtils.enableApiWol,
HttpServerUtils.enableApiLocation,

@ -1,29 +1,67 @@
package com.idormy.sms.forwarder.server.controller
import android.util.Log
import com.idormy.sms.forwarder.entity.ContactInfo
import com.idormy.sms.forwarder.server.model.BaseRequest
import com.idormy.sms.forwarder.server.model.ContactQueryData
import com.idormy.sms.forwarder.utils.PhoneUtils
import com.yanzhenjie.andserver.annotation.*
@Suppress("PrivatePropertyName")
@RestController
@RequestMapping(path = ["/contact"])
class ContactController {
private val TAG: String = ContactController::class.java.simpleName
//远程查话簿
@CrossOrigin(methods = [RequestMethod.POST])
@PostMapping("/query")
fun query(@RequestBody bean: BaseRequest<ContactQueryData>): MutableList<ContactInfo> {
val contactQueryData = bean.data
Log.d(TAG, contactQueryData.toString())
val limit = contactQueryData.pageSize
val offset = (contactQueryData.pageNum - 1) * limit
return PhoneUtils.getContactInfoList(limit, offset, contactQueryData.phoneNumber, contactQueryData.name)
}
package com.idormy.sms.forwarder.server.controller
import android.content.ContentUris
import android.content.ContentValues
import android.provider.ContactsContract
import android.util.Log
import com.idormy.sms.forwarder.entity.ContactInfo
import com.idormy.sms.forwarder.server.model.BaseRequest
import com.idormy.sms.forwarder.server.model.ContactQueryData
import com.idormy.sms.forwarder.utils.PhoneUtils
import com.xuexiang.xutil.XUtil.getContentResolver
import com.yanzhenjie.andserver.annotation.*
@Suppress("PrivatePropertyName")
@RestController
@RequestMapping(path = ["/contact"])
class ContactController {
private val TAG: String = ContactController::class.java.simpleName
//远程查话簿
@CrossOrigin(methods = [RequestMethod.POST])
@PostMapping("/query")
fun query(@RequestBody bean: BaseRequest<ContactQueryData>): MutableList<ContactInfo> {
val contactQueryData = bean.data
Log.d(TAG, contactQueryData.toString())
val limit = contactQueryData.pageSize
val offset = (contactQueryData.pageNum - 1) * limit
return PhoneUtils.getContactInfoList(limit, offset, contactQueryData.phoneNumber, contactQueryData.name)
}
//远程加话簿
@CrossOrigin(methods = [RequestMethod.POST])
@PostMapping("/add")
fun add(@RequestBody bean: BaseRequest<ContactInfo>): String {
val contactData = bean.data
Log.d(TAG, contactData.toString())
//创建一个空的ContentValues
val values = ContentValues()
//首先向RawContacts.CONTENT_URI执行一个空值插入目的是获取系统返回的rawContactId
val rawcontacturi = getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values)
val rawcontactid = ContentUris.parseId(rawcontacturi!!)
//插入姓名数据
values.clear()
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawcontactid)
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, contactData.name)
getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values)
//插入电话数据
for (phoneNumber in contactData.phoneNumber.split(";")) {
values.clear()
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawcontactid)
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber)
values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values)
}
return "success"
}
}

@ -15,6 +15,8 @@ data class ConfigData(
var enableApiCallQuery: Boolean = false,
@SerializedName("enable_api_contact_query")
var enableApiContactQuery: Boolean = false,
@SerializedName("enable_api_contact_add")
var enableApiContactAdd: Boolean = false,
@SerializedName("enable_api_battery_query")
var enableApiBatteryQuery: Boolean = false,
@SerializedName("enable_api_wol")

@ -356,6 +356,7 @@ const val SP_ENABLE_API_SMS_SEND = "enable_api_sms_send"
const val SP_ENABLE_API_SMS_QUERY = "enable_api_sms_query"
const val SP_ENABLE_API_CALL_QUERY = "enable_api_call_query"
const val SP_ENABLE_API_CONTACT_QUERY = "enable_api_contact_query"
const val SP_ENABLE_API_CONTACT_ADD = "enable_api_contact_add"
const val SP_ENABLE_API_BATTERY_QUERY = "enable_api_battery_query"
const val SP_ENABLE_API_WOL = "enable_api_wol"
const val SP_ENABLE_API_LOCATION = "enable_api_location"
@ -376,18 +377,18 @@ var CLIENT_FRAGMENT_LIST = listOf(
R.drawable.icon_api_clone
),
PageInfo(
getString(R.string.api_sms_send),
"com.idormy.sms.forwarder.fragment.client.SmsSendFragment",
getString(R.string.api_sms_query),
"com.idormy.sms.forwarder.fragment.client.SmsQueryFragment",
"{\"\":\"\"}",
CoreAnim.slide,
R.drawable.icon_api_sms_send
R.drawable.icon_api_sms_query
),
PageInfo(
getString(R.string.api_sms_query),
"com.idormy.sms.forwarder.fragment.client.SmsQueryFragment",
getString(R.string.api_sms_send),
"com.idormy.sms.forwarder.fragment.client.SmsSendFragment",
"{\"\":\"\"}",
CoreAnim.slide,
R.drawable.icon_api_sms_query
R.drawable.icon_api_sms_send
),
PageInfo(
getString(R.string.api_call_query),
@ -404,11 +405,11 @@ var CLIENT_FRAGMENT_LIST = listOf(
R.drawable.icon_api_contact_query
),
PageInfo(
getString(R.string.api_battery_query),
"com.idormy.sms.forwarder.fragment.client.BatteryQueryFragment",
getString(R.string.api_contact_add),
"com.idormy.sms.forwarder.fragment.client.ContactAddFragment",
"{\"\":\"\"}",
CoreAnim.slide,
R.drawable.icon_api_battery_query
R.drawable.icon_api_contact_add
),
PageInfo(
getString(R.string.api_wol),
@ -424,4 +425,11 @@ var CLIENT_FRAGMENT_LIST = listOf(
CoreAnim.slide,
R.drawable.icon_api_location
),
PageInfo(
getString(R.string.api_battery_query),
"com.idormy.sms.forwarder.fragment.client.BatteryQueryFragment",
"{\"\":\"\"}",
CoreAnim.slide,
R.drawable.icon_api_battery_query
),
)

@ -79,6 +79,9 @@ class HttpServerUtils private constructor() {
//是否启用远程查话簿
var enableApiContactQuery: Boolean by SharedPreference(SP_ENABLE_API_CONTACT_QUERY, true)
//是否启用远程加话簿
var enableApiContactAdd: Boolean by SharedPreference(SP_ENABLE_API_CONTACT_ADD, true)
//是否启用远程查电量
var enableApiBatteryQuery: Boolean by SharedPreference(SP_ENABLE_API_BATTERY_QUERY, true)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/xui_config_color_background"
android:orientation="vertical">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:contentDescription="@string/api_contact_add"
app:srcCompat="@drawable/icon_api_contact_add" />
<LinearLayout
style="@style/senderBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/phone_numbers" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_phone_numbers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/phone_numbers_hint"
android:singleLine="true"
app:met_clearButton="true"
app:met_errorMessage="@string/phone_numbers_error"
app:met_regexp="@string/phone_numbers_regex"
app:met_validateOnFocusLost="true" />
</LinearLayout>
<LinearLayout
style="@style/senderBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/display_name" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_display_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/display_name_hint"
android:singleLine="true"
app:met_clearButton="true" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp">
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_submit"
style="@style/SuperButton.Blue.Icon"
android:drawableStart="@drawable/ic_send_white"
android:paddingStart="20dp"
android:text="@string/send"
tools:ignore="RtlSymmetry" />
</LinearLayout>
</LinearLayout>

@ -535,21 +535,21 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_sms_send"
android:text="@string/api_sms_query"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_sms_send_tips"
android:text="@string/api_sms_query_tips"
android:textSize="9sp"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_send_sms"
android:id="@+id/sb_api_query_sms"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
@ -570,21 +570,21 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_sms_query"
android:text="@string/api_sms_send"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_sms_query_tips"
android:text="@string/api_sms_send_tips"
android:textSize="9sp"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_query_sms"
android:id="@+id/sb_api_send_sms"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
@ -664,8 +664,7 @@
<LinearLayout
style="@style/settingBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="TooManyViews">
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="0dp"
@ -676,21 +675,21 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_battery_query"
android:text="@string/api_contact_add"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_battery_query_tips"
android:text="@string/api_contact_add_tips"
android:textSize="9sp"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_query_battery"
android:id="@+id/sb_api_add_contacts"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
@ -767,6 +766,42 @@
</LinearLayout>
<LinearLayout
style="@style/settingBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="TooManyViews">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_battery_query"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_battery_query_tips"
android:textSize="9sp"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_query_battery"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

@ -804,6 +804,8 @@
<string name="api_call_query_tips">Remotely check call records, including incoming calls, outgoing calls, and missed calls</string>
<string name="api_contact_query">Query Linkman</string>
<string name="api_contact_query_tips">Remotely check contact list</string>
<string name="api_contact_add">Add Linkman</string>
<string name="api_contact_add_tips">Remotely add contact</string>
<string name="api_battery_query">Query Battery</string>
<string name="api_battery_query_tips">Remotely query mobile phone power and battery status</string>
<string name="api_wol">Remotely WOL</string>
@ -817,6 +819,8 @@
<string name="location_provider">Provider%s</string>
<string name="sim_slot">Sim Slot</string>
<string name="display_name">Display Name</string>
<string name="display_name_hint">Optional, address book display name</string>
<string name="phone_numbers">Phone Numbers</string>
<string name="phone_numbers_hint">Required, separate multiple phone numbers with semicolons</string>
<string name="phone_numbers_error">Invalid Phone Numbers, eg. 15888888888;19999999999</string>

@ -805,6 +805,8 @@
<string name="api_call_query_tips">远程查通话记录,包括来电、去电、未接电话</string>
<string name="api_contact_query">远程查话簿</string>
<string name="api_contact_query_tips">远程查联系人列表</string>
<string name="api_contact_add">远程加话簿</string>
<string name="api_contact_add_tips">远程添加联系人</string>
<string name="api_battery_query">远程查电量</string>
<string name="api_battery_query_tips">远程查询手机电量与电池状态</string>
<string name="api_wol">远程WOL</string>
@ -818,6 +820,8 @@
<string name="location_provider">供应商:%s</string>
<string name="sim_slot">发送卡槽</string>
<string name="display_name">姓名</string>
<string name="display_name_hint">选填,通讯录显示名称</string>
<string name="phone_numbers">手机号码</string>
<string name="phone_numbers_hint">必填,多个手机号用半角分号分隔</string>
<string name="phone_numbers_error">手机号码格式错误15888888888;19999999999</string>

Loading…
Cancel
Save