新增:远程查询手机定位(方便找回手机/防止老少走丢) #256
parent
3f28080958
commit
7bc7bfa514
@ -0,0 +1,25 @@
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.xuexiang.xui.utils.ResUtils
|
||||
import java.io.Serializable
|
||||
|
||||
data class LocationInfo(
|
||||
var longitude: Double = 0.0,
|
||||
var latitude: Double = 0.0,
|
||||
var address: String = "",
|
||||
var time: String = "",
|
||||
var provider: String = ""
|
||||
) : Serializable {
|
||||
|
||||
override fun toString(): String {
|
||||
var msg = ""
|
||||
msg += "\n" + String.format(ResUtils.getString(R.string.location_longitude), longitude)
|
||||
msg += "\n" + String.format(ResUtils.getString(R.string.location_latitude), latitude)
|
||||
if (address != "") msg += "\n" + String.format(ResUtils.getString(R.string.location_address), address)
|
||||
if (time != "") msg += "\n" + String.format(ResUtils.getString(R.string.location_time), time)
|
||||
if (provider != "") msg += "\n" + String.format(ResUtils.getString(R.string.location_provider), provider)
|
||||
return msg
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
package com.idormy.sms.forwarder.fragment.client
|
||||
|
||||
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.FragmentClientLocationBinding
|
||||
import com.idormy.sms.forwarder.entity.LocationInfo
|
||||
import com.idormy.sms.forwarder.server.model.BaseResponse
|
||||
import com.idormy.sms.forwarder.utils.*
|
||||
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.xui.widget.grouplist.XUIGroupListView
|
||||
import com.xuexiang.xutil.data.ConvertTools
|
||||
|
||||
@Suppress("PropertyName")
|
||||
@Page(name = "远程找手机")
|
||||
class LocationFragment : BaseFragment<FragmentClientLocationBinding?>(), View.OnClickListener {
|
||||
|
||||
val TAG: String = LocationFragment::class.java.simpleName
|
||||
private var mCountDownHelper: CountDownButtonHelper? = null
|
||||
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentClientLocationBinding {
|
||||
return FragmentClientLocationBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
return super.initTitle()!!.setImmersive(false).setTitle(R.string.api_location)
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化控件
|
||||
*/
|
||||
override fun initViews() {
|
||||
//发送按钮增加倒计时,避免重复点击
|
||||
mCountDownHelper = CountDownButtonHelper(binding!!.btnRefresh, SettingUtils.requestTimeout)
|
||||
mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener {
|
||||
override fun onCountDown(time: Int) {
|
||||
binding!!.btnRefresh.text = String.format(getString(R.string.seconds_n), time)
|
||||
}
|
||||
|
||||
override fun onFinished() {
|
||||
binding!!.btnRefresh.text = getString(R.string.refresh)
|
||||
}
|
||||
})
|
||||
|
||||
getLocation()
|
||||
}
|
||||
|
||||
override fun initListeners() {
|
||||
binding!!.btnRefresh.setOnClickListener(this)
|
||||
}
|
||||
|
||||
@SingleClick
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.btn_refresh -> {
|
||||
getLocation()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLocation() {
|
||||
val requestUrl: String = HttpServerUtils.serverAddress + "/location/query"
|
||||
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 dataMap: MutableMap<String, Any> = mutableMapOf()
|
||||
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 -> {
|
||||
try {
|
||||
val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey)
|
||||
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<LocationInfo> = Gson().fromJson(json, object : TypeToken<BaseResponse<LocationInfo>>() {}.type)
|
||||
if (resp.code == 200) {
|
||||
XToastUtils.success(ResUtils.getString(R.string.request_succeeded))
|
||||
mCountDownHelper?.finish()
|
||||
|
||||
val locationInfo = resp.data ?: return
|
||||
|
||||
val groupListView = binding!!.infoList
|
||||
groupListView.removeAllViews()
|
||||
val section = XUIGroupListView.newSection(context)
|
||||
section.addItemView(groupListView.createItemView(String.format(ResUtils.getString(R.string.location_longitude), locationInfo.longitude))) {}
|
||||
section.addItemView(groupListView.createItemView(String.format(ResUtils.getString(R.string.location_latitude), locationInfo.latitude))) {}
|
||||
if (locationInfo.address != "") section.addItemView(groupListView.createItemView(String.format(ResUtils.getString(R.string.location_address), locationInfo.address))) {}
|
||||
if (locationInfo.time != "") section.addItemView(groupListView.createItemView(String.format(ResUtils.getString(R.string.location_time), locationInfo.time))) {}
|
||||
if (locationInfo.provider != "") section.addItemView(groupListView.createItemView(String.format(ResUtils.getString(R.string.location_provider), locationInfo.provider))) {}
|
||||
section.addTo(groupListView)
|
||||
} 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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
if (mCountDownHelper != null) mCountDownHelper!!.recycle()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.idormy.sms.forwarder.server.controller
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.util.Log
|
||||
import com.idormy.sms.forwarder.entity.LocationInfo
|
||||
import com.idormy.sms.forwarder.server.model.BaseRequest
|
||||
import com.idormy.sms.forwarder.server.model.EmptyData
|
||||
import com.idormy.sms.forwarder.utils.HttpServerUtils
|
||||
import com.yanzhenjie.andserver.annotation.*
|
||||
import java.util.*
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
@Suppress("PrivatePropertyName", "DEPRECATION")
|
||||
@RestController
|
||||
@RequestMapping(path = ["/location"])
|
||||
class LocationController {
|
||||
|
||||
private val TAG: String = LocationController::class.java.simpleName
|
||||
|
||||
//远程找手机
|
||||
@CrossOrigin(methods = [RequestMethod.POST])
|
||||
@PostMapping("/query")
|
||||
fun query(@RequestBody bean: BaseRequest<EmptyData>): LocationInfo {
|
||||
Log.d(TAG, bean.data.toString())
|
||||
return HttpServerUtils.apiLocationCache
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB |
@ -0,0 +1,58 @@
|
||||
<?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_location"
|
||||
app:srcCompat="@drawable/icon_api_location" />
|
||||
|
||||
<com.xuexiang.xui.widget.grouplist.XUIGroupListView
|
||||
android:id="@+id/info_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical" />
|
||||
|
||||
</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_refresh"
|
||||
style="@style/SuperButton.Blue.Icon"
|
||||
android:layout_marginStart="20dp"
|
||||
android:drawableStart="@drawable/ic_refresh"
|
||||
android:paddingStart="20dp"
|
||||
android:text="@string/refresh"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
Loading…
Reference in New Issue