[*] 地理位置

This commit is contained in:
acgist
2023-03-23 08:11:36 +08:00
parent d635b5a2a3
commit 1fb36da847
13 changed files with 234 additions and 99 deletions

View File

@@ -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'

View File

@@ -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;
}
}

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -68,4 +68,8 @@ public class MessageCodeException extends RuntimeException {
this.code = code;
}
public MessageCode getCode() {
return this.code;
}
}

View File

@@ -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
}
}

View File

@@ -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'

View File

@@ -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"

View File

@@ -1,4 +0,0 @@
package com.acgist.taoyao.client.media;
public class MediaRecorder {
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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'