[*] 地理位置
This commit is contained in:
@@ -25,6 +25,8 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
implementation 'org.apache.commons:commons-collections4:4.4'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
||||
@@ -39,7 +39,7 @@ public class Header implements Serializable {
|
||||
}
|
||||
|
||||
public String getV() {
|
||||
return v;
|
||||
return this.v;
|
||||
}
|
||||
|
||||
public void setV(String v) {
|
||||
@@ -47,7 +47,7 @@ public class Header implements Serializable {
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
@@ -55,10 +55,11 @@ public class Header implements Serializable {
|
||||
}
|
||||
|
||||
public String getSignal() {
|
||||
return signal;
|
||||
return this.signal;
|
||||
}
|
||||
|
||||
public void setSignal(String signal) {
|
||||
this.signal = signal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.acgist.taoyao.boot.model;
|
||||
|
||||
import com.acgist.taoyao.boot.utils.JSONUtils;
|
||||
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.acgist.taoyao.boot.utils.JSONUtils;
|
||||
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
|
||||
|
||||
|
||||
/**
|
||||
* 消息
|
||||
@@ -36,13 +38,6 @@ public class Message implements Cloneable, Serializable {
|
||||
*/
|
||||
private Object body;
|
||||
|
||||
/**
|
||||
* @param code 状态编码
|
||||
*/
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param code 状态编码
|
||||
*/
|
||||
@@ -57,7 +52,7 @@ public class Message implements Cloneable, Serializable {
|
||||
*/
|
||||
public Message setCode(MessageCode code, String message) {
|
||||
this.code = code.getCode();
|
||||
this.message = message == null || message.isEmpty() ? code.getMessage() : message;
|
||||
this.message = StringUtils.isEmpty(message) ? code.getMessage() : message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -186,11 +181,15 @@ public class Message implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
return this.message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
@@ -198,7 +197,7 @@ public class Message implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
public Header getHeader() {
|
||||
return header;
|
||||
return this.header;
|
||||
}
|
||||
|
||||
public void setHeader(Header header) {
|
||||
@@ -206,7 +205,7 @@ public class Message implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
public Object getBody() {
|
||||
return body;
|
||||
return this.body;
|
||||
}
|
||||
|
||||
public void setBody(Object body) {
|
||||
|
||||
@@ -84,14 +84,15 @@ public enum MessageCode {
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
return this.message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,4 +68,8 @@ public class MessageCodeException extends RuntimeException {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public MessageCode getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
plugins {
|
||||
id 'com.android.library' version '7.4.2' apply false
|
||||
id 'com.android.application' version '7.4.2' apply false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
implementation 'org.apache.commons:commons-collections4:4.4'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package com.acgist.taoyao.client.media;
|
||||
|
||||
public class MediaRecorder {
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.acgist.taoyao.client.media;
|
||||
|
||||
/**
|
||||
* 录像机
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
public final class Recorder {
|
||||
|
||||
/**
|
||||
* 是否正在录像
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
private static final Recorder INSTANCE = new Recorder();
|
||||
|
||||
public static final Recorder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否正在录像
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,20 @@
|
||||
package com.acgist.taoyao.client.signal;
|
||||
|
||||
import android.location.Criteria;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.BatteryManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.acgist.taoyao.boot.model.Header;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.boot.utils.CloseableUtils;
|
||||
import com.acgist.taoyao.boot.utils.JSONUtils;
|
||||
import com.acgist.taoyao.client.media.Recorder;
|
||||
import com.acgist.taoyao.client.utils.IdUtils;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -15,7 +23,6 @@ import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -33,11 +40,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
public class Taoyao {
|
||||
|
||||
// private static final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0, "[信令]");
|
||||
|
||||
private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(8);
|
||||
public final class Taoyao {
|
||||
|
||||
/**
|
||||
* 端口
|
||||
@@ -47,10 +50,24 @@ public class Taoyao {
|
||||
* 地址
|
||||
*/
|
||||
private final String host;
|
||||
/**
|
||||
* 终端ID
|
||||
*/
|
||||
private final String clientId;
|
||||
private final String clientType = "camera";
|
||||
/**
|
||||
* 终端名称
|
||||
*/
|
||||
private final String name;
|
||||
/**
|
||||
* 桃夭帐号
|
||||
*/
|
||||
private final String username;
|
||||
/**
|
||||
* 桃夭密码
|
||||
*/
|
||||
private final String password;
|
||||
private String version;
|
||||
/**
|
||||
* Socket
|
||||
*/
|
||||
@@ -66,10 +83,15 @@ public class Taoyao {
|
||||
private final Cipher decrypt;
|
||||
private final WifiManager wifiManager;
|
||||
private final BatteryManager batteryManager;
|
||||
private final LocationManager locationManager;
|
||||
// 线程池
|
||||
private final ExecutorService executor = Executors.newFixedThreadPool(8);
|
||||
// 定时任务线程池
|
||||
private final ExecutorService scheduled = Executors.newScheduledThreadPool(2);
|
||||
|
||||
public Taoyao(
|
||||
int port, String host, String algo, String secret, String clientId, String name, String username, String password,
|
||||
WifiManager wifiManager, BatteryManager batteryManager
|
||||
WifiManager wifiManager, BatteryManager batteryManager, LocationManager locationManager
|
||||
) {
|
||||
this.port = port;
|
||||
this.host = host;
|
||||
@@ -89,7 +111,9 @@ public class Taoyao {
|
||||
this.password = password;
|
||||
this.wifiManager = wifiManager;
|
||||
this.batteryManager = batteryManager;
|
||||
EXECUTOR.submit(this::read);
|
||||
this.locationManager = locationManager;
|
||||
executor.submit(this::read);
|
||||
scheduled.submit(this::heartbeat);
|
||||
}
|
||||
|
||||
private Cipher buildCipher(int mode, String name, String secret) {
|
||||
@@ -128,6 +152,10 @@ public class Taoyao {
|
||||
}
|
||||
}
|
||||
|
||||
private void heartbeat() {
|
||||
|
||||
}
|
||||
|
||||
private void read() {
|
||||
int length = 0;
|
||||
short messageLength = 0;
|
||||
@@ -167,8 +195,12 @@ public class Taoyao {
|
||||
buffer.get(message);
|
||||
buffer.compact();
|
||||
final String content = new String(this.decrypt.doFinal(message));
|
||||
EXECUTOR.submit(() -> {
|
||||
Taoyao.this.on(content);
|
||||
executor.submit(() -> {
|
||||
try {
|
||||
Taoyao.this.on(content);
|
||||
} catch (Exception e) {
|
||||
Log.e(Taoyao.class.getSimpleName(), "处理信令异常:" + content, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -224,25 +256,9 @@ public class Taoyao {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void register() {
|
||||
final Header header = new Header();
|
||||
this.push(this.buildMessage(
|
||||
"client::register",
|
||||
"clientId", this.clientId,
|
||||
"name", this.name,
|
||||
"clientType", "camera",
|
||||
"username", this.username,
|
||||
"password", this.password,
|
||||
"signal", this.wifiManager.getMaxSignalLevel(),
|
||||
"batter", this.batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY),
|
||||
"charging", this.batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS)
|
||||
));
|
||||
}
|
||||
|
||||
private void heartbeat() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放连接
|
||||
*/
|
||||
private void close() {
|
||||
this.connect = false;
|
||||
CloseableUtils.close(this.input);
|
||||
@@ -253,46 +269,25 @@ public class Taoyao {
|
||||
this.socket = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭信令
|
||||
*/
|
||||
private void shutdown() {
|
||||
this.close();
|
||||
this.close = true;
|
||||
EXECUTOR.shutdownNow();
|
||||
executor.shutdownNow();
|
||||
scheduled.shutdownNow();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前索引
|
||||
* @param signal 信令
|
||||
* @param args 消息主体内容
|
||||
*
|
||||
* @return 消息
|
||||
*/
|
||||
private int index;
|
||||
/**
|
||||
* 当前终端索引
|
||||
*/
|
||||
private int clientIndex = 99999;
|
||||
|
||||
private static final int MAX_INDEX = 999;
|
||||
|
||||
public long buildId() {
|
||||
int index;
|
||||
synchronized (this) {
|
||||
if (++this.index > MAX_INDEX) {
|
||||
this.index = 0;
|
||||
}
|
||||
index = this.index;
|
||||
}
|
||||
final LocalDateTime time = LocalDateTime.now();
|
||||
return
|
||||
100000000000000L * time.getDayOfMonth() +
|
||||
1000000000000L * time.getHour() +
|
||||
10000000000L * time.getMinute() +
|
||||
100000000L * time.getSecond() +
|
||||
1000000L * this.clientIndex +
|
||||
index;
|
||||
}
|
||||
|
||||
private String version;
|
||||
|
||||
public Message buildMessage(String signal, Object... args) {
|
||||
public Message buildMessage(String signal, Object ... args) {
|
||||
final Map<Object, Object> map = new HashMap<>();
|
||||
if (args != null) {
|
||||
if (ArrayUtils.isNotEmpty(args)) {
|
||||
for (int index = 0; index < args.length; index += 2) {
|
||||
map.put(args[index], args[index + 1]);
|
||||
}
|
||||
@@ -300,21 +295,28 @@ public class Taoyao {
|
||||
return this.buildMessage(signal, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param signal 信令
|
||||
* @param body 消息主体
|
||||
*
|
||||
* @return 消息
|
||||
*/
|
||||
public Message buildMessage(String signal, Object body) {
|
||||
final Header header = new Header();
|
||||
header.setV(this.version == null ? "1.0.0" : this.version);
|
||||
header.setId(this.buildId());
|
||||
header.setId(IdUtils.buildId());
|
||||
header.setSignal(signal);
|
||||
final Message message = new Message();
|
||||
message.setHeader(header);
|
||||
message.setBody(body == null ? new HashMap<>() : body);
|
||||
message.setBody(body == null ? Map.of() : body);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param content 信令消息
|
||||
*/
|
||||
private void on(String content) {
|
||||
// TODO:日志
|
||||
// log.debug("收到消息:{}", new String(this.decrypt.doFinal(message)));
|
||||
System.out.println(content);
|
||||
Log.d(Taoyao.class.getSimpleName(), "收到消息:" + content);
|
||||
final Message message = JSONUtils.toJava(content, Message.class);
|
||||
if (message == null) {
|
||||
return;
|
||||
@@ -325,18 +327,61 @@ public class Taoyao {
|
||||
}
|
||||
final Map<String, Object> body = message.body();
|
||||
switch (header.getSignal()) {
|
||||
case "client::register":
|
||||
this.register(message, body);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case "client::register" -> this.register(message, body);
|
||||
default -> Log.i(Taoyao.class.getSimpleName(), "没有适配信令:" + content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
private void register() {
|
||||
final Location location = this.location();
|
||||
this.push(this.buildMessage(
|
||||
"client::register",
|
||||
"username", this.username,
|
||||
"password", this.password,
|
||||
"name", this.name,
|
||||
"clientId", this.clientId,
|
||||
"clientType", this.clientType,
|
||||
"latitude", location == null ? -1 : location.getLatitude(),
|
||||
"longitude", location == null ? -1 : location.getLongitude(),
|
||||
"signal", this.wifiManager == null ? -1 : this.wifiManager.getMaxSignalLevel(),
|
||||
"batter", this.batteryManager == null ? -1 : this.batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY),
|
||||
"charging", this.batteryManager == null ? -1 : this.batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS),
|
||||
"recording", Recorder.getInstance().isActive()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message 消息
|
||||
* @param body 消息主体
|
||||
*/
|
||||
private void register(Message message, Map<String, Object> body) {
|
||||
final Integer index = (Integer) body.get("index");
|
||||
this.clientIndex = index;
|
||||
System.out.println(clientIndex);
|
||||
IdUtils.setClientIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 位置
|
||||
*/
|
||||
private Location location() {
|
||||
if(this.locationManager == null) {
|
||||
return null;
|
||||
}
|
||||
final Criteria criteria = new Criteria();
|
||||
// 耗电
|
||||
criteria.setCostAllowed(false);
|
||||
// 不要海拔
|
||||
criteria.setAltitudeRequired(false);
|
||||
// 不要方位
|
||||
criteria.setBearingRequired(false);
|
||||
// 精度
|
||||
criteria.setAccuracy(Criteria.ACCURACY_FINE);
|
||||
// 低功耗
|
||||
criteria.setPowerRequirement(Criteria.POWER_LOW);
|
||||
final String provider = locationManager.getBestProvider(criteria, true);
|
||||
return this.locationManager.getLastKnownLocation(provider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.acgist.taoyao.client.utils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* ID工具
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
public final class IdUtils {
|
||||
|
||||
/**
|
||||
* 当前索引
|
||||
*/
|
||||
private static int index;
|
||||
/**
|
||||
* 当前终端索引
|
||||
*/
|
||||
private static int clientIndex = 99999;
|
||||
/**
|
||||
* 最大索引
|
||||
*/
|
||||
private static final int MAX_INDEX = 999;
|
||||
|
||||
/**
|
||||
* @return 消息ID
|
||||
*/
|
||||
public static final long buildId() {
|
||||
int index;
|
||||
synchronized (IdUtils.class) {
|
||||
if (++IdUtils.index > IdUtils.MAX_INDEX) {
|
||||
IdUtils.index = 0;
|
||||
}
|
||||
index = IdUtils.index;
|
||||
}
|
||||
final LocalDateTime time = LocalDateTime.now();
|
||||
return
|
||||
100000000000000L * time.getDayOfMonth() +
|
||||
1000000000000L * time.getHour() +
|
||||
10000000000L * time.getMinute() +
|
||||
100000000L * time.getSecond() +
|
||||
1000000L * IdUtils.clientIndex +
|
||||
index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientIndex 当前终端索引
|
||||
*/
|
||||
public static final void setClientIndex(int clientIndex) {
|
||||
IdUtils.clientIndex = clientIndex;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,6 +48,8 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.a', '*.so', '*.jar'])
|
||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
implementation 'org.apache.commons:commons-collections4:4.4'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
||||
Reference in New Issue
Block a user