refactor(mqtt): 优化MQTT连接管理与设备状态上报
- 使用DeviceStatus对象替代手动拼接JSON字符串 - 启用HiveMQ自动重连机制,移除自定义重连逻辑 - 添加连接状态标记防止并发重复建连 - 优化断线回调,记录服务端断开原因 - 使用设备序列号作为MQTT客户端标识 - 新增信号强度和真实屏幕分辨率获取方法 - 修复SystemUtils中系统属性获取方式 - 添加DeviceStatus单元测试
This commit is contained in:
@@ -18,6 +18,8 @@ import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
@@ -26,9 +28,13 @@ import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.CellInfo;
|
||||
import android.telephony.CellSignalStrength;
|
||||
import android.telephony.SignalStrength;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
@@ -78,15 +84,14 @@ public class SystemUtils {
|
||||
* @return
|
||||
*/
|
||||
public static String getProperty(String key, String defaultValue) {
|
||||
String value = defaultValue;
|
||||
// SystemProperties.get();
|
||||
try {
|
||||
Class<?> c = Class.forName("android.os.SystemProperties");
|
||||
Method get = c.getMethod("get", String.class, String.class);
|
||||
value = (String) (get.invoke(c, key, Build.UNKNOWN));
|
||||
return (String) (get.invoke(c, key, defaultValue));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
return value;
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,6 +371,135 @@ public class SystemUtils {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前蜂窝信号强度等级(0~4,对应 ASU 的粗略分级,4 最强)。
|
||||
* 该值可用于状态栏信号格显示,与 {@link android.telephony.SignalStrength#getLevel()} 一致。
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 信号等级 0~4;无 SIM / 非蜂窝网络 / 获取失败返回 -1
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
public static int getSignalLevel(Context context) {
|
||||
try {
|
||||
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (tm == null) {
|
||||
return -1;
|
||||
}
|
||||
// Android 9 (API 28) 及以下无 getAllCellInfo/SignalStrength 的公开 getLevel,
|
||||
// 这里统一用 getAllCellInfo 取最强小区的 level,覆盖绝大多数系统版本。
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
List<CellInfo> cellInfos = tm.getAllCellInfo();
|
||||
if (cellInfos != null) {
|
||||
int maxLevel = -1;
|
||||
for (CellInfo info : cellInfos) {
|
||||
if (info == null || !info.isRegistered()) {
|
||||
continue;
|
||||
}
|
||||
CellSignalStrength strength = info.getCellSignalStrength();
|
||||
if (strength != null) {
|
||||
maxLevel = Math.max(maxLevel, strength.getLevel());
|
||||
}
|
||||
}
|
||||
if (maxLevel >= 0) {
|
||||
return maxLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 兜底:API 29+ 可直接取 SignalStrength 的 level
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
SignalStrength signalStrength = tm.getSignalStrength();
|
||||
if (signalStrength != null) {
|
||||
return signalStrength.getLevel();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前蜂窝信号强度(dBm,如 -75 表示较强,-113 接近无信号)。
|
||||
* 优先使用各制式 CellInfo 的 dBm,找不到则回退到 ASU 换算(asu - 113 - 2 * (asu & 1))。
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 信号强度 dBm;无信号 / 获取失败返回 {@code null}
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
public static Integer getSignalDbm(Context context) {
|
||||
try {
|
||||
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (tm == null) {
|
||||
return null;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
List<CellInfo> cellInfos = tm.getAllCellInfo();
|
||||
if (cellInfos != null) {
|
||||
int bestDbm = Integer.MIN_VALUE;
|
||||
for (CellInfo info : cellInfos) {
|
||||
if (info == null || !info.isRegistered()) {
|
||||
continue;
|
||||
}
|
||||
CellSignalStrength strength = info.getCellSignalStrength();
|
||||
if (strength != null) {
|
||||
int dbm = strength.getDbm();
|
||||
if (dbm != Integer.MAX_VALUE && dbm > bestDbm) {
|
||||
bestDbm = dbm;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestDbm != Integer.MIN_VALUE) {
|
||||
return bestDbm;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
SignalStrength signalStrength = tm.getSignalStrength();
|
||||
if (signalStrength != null) {
|
||||
int dbm = signalStrength.getDbm();
|
||||
if (dbm != Integer.MAX_VALUE && dbm != Integer.MIN_VALUE) {
|
||||
return dbm;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据当前活跃网络获取信号强度 (RSSI/dBm)
|
||||
* 优先返回 Wi-Fi 信号强度,如果未连接 Wi-Fi 则返回移动网络信号强度
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 信号强度 (dBm);获取失败返回 null
|
||||
*/
|
||||
public static Integer getCurrentNetworkRssi(Context context) {
|
||||
try {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (cm == null) return null;
|
||||
|
||||
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
|
||||
if (activeNetwork == null || !activeNetwork.isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
|
||||
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
WifiInfo info = wifiManager.getConnectionInfo();
|
||||
if (info != null) {
|
||||
return info.getRssi();
|
||||
}
|
||||
} else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
|
||||
return getSignalDbm(context);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getNetworkTypeName(int networkType) {
|
||||
switch (networkType) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
@@ -504,11 +638,11 @@ public class SystemUtils {
|
||||
}
|
||||
|
||||
public static String getBuildId() {
|
||||
return getProperty(Build.ID, Build.UNKNOWN);
|
||||
return getProperty("ro.build.id", Build.ID);
|
||||
}
|
||||
|
||||
public static String getBuildDisplayId() {
|
||||
return getProperty(Build.DISPLAY, Build.UNKNOWN);
|
||||
return getProperty("ro.build.display.id", Build.DISPLAY);
|
||||
}
|
||||
|
||||
// ==================================================================
|
||||
@@ -527,7 +661,7 @@ public class SystemUtils {
|
||||
}
|
||||
|
||||
public static String getDeviceManufacturer() {
|
||||
return getProperty(Build.MANUFACTURER, Build.UNKNOWN);
|
||||
return getProperty("ro.product.manufacturer", Build.MANUFACTURER);
|
||||
}
|
||||
|
||||
public static String getHardware() {
|
||||
@@ -535,7 +669,7 @@ public class SystemUtils {
|
||||
}
|
||||
|
||||
public static String getHost() {
|
||||
return getProperty(Build.HOST, Build.UNKNOWN);
|
||||
return getProperty("ro.build.host", Build.HOST);
|
||||
}
|
||||
|
||||
public static String getAndroidId(Context context) {
|
||||
@@ -547,23 +681,23 @@ public class SystemUtils {
|
||||
}
|
||||
|
||||
public static String getBuildFingerprint() {
|
||||
return getProperty(Build.FINGERPRINT, Build.UNKNOWN);
|
||||
return getProperty("ro.build.fingerprint", Build.FINGERPRINT);
|
||||
}
|
||||
|
||||
public static String getBuildType() {
|
||||
return getProperty(Build.TYPE, Build.UNKNOWN);
|
||||
return getProperty("ro.build.type", Build.TYPE);
|
||||
}
|
||||
|
||||
public static String getBuildUser() {
|
||||
return getProperty(Build.USER, Build.UNKNOWN);
|
||||
return getProperty("ro.build.user", Build.USER);
|
||||
}
|
||||
|
||||
public static String getBuildHost() {
|
||||
return getProperty(Build.HOST, Build.UNKNOWN);
|
||||
return getProperty("ro.build.host", Build.HOST);
|
||||
}
|
||||
|
||||
public static String getBuildTags() {
|
||||
return getProperty(Build.TAGS, Build.UNKNOWN);
|
||||
return getProperty("ro.build.tags", Build.TAGS);
|
||||
}
|
||||
|
||||
public static long getBuildTime() {
|
||||
@@ -600,13 +734,30 @@ public class SystemUtils {
|
||||
|
||||
public static String getScreenResolution(Context context) {
|
||||
try {
|
||||
android.util.DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
android.util.DisplayMetrics dm = getRealDisplayMetrics(context);
|
||||
return dm.widthPixels + "x" + dm.heightPixels;
|
||||
} catch (Throwable t) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备真实屏幕显示参数(包含状态栏、导航栏,不被窗口裁切)。
|
||||
* 优先使用 getRealMetrics(显示设备真实分辨率),低版本无此 API 时回退 getMetrics。
|
||||
*/
|
||||
private static android.util.DisplayMetrics getRealDisplayMetrics(Context context) {
|
||||
android.util.DisplayMetrics dm = new android.util.DisplayMetrics();
|
||||
android.view.WindowManager wm =
|
||||
(android.view.WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
android.view.Display display = wm.getDefaultDisplay();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
display.getRealMetrics(dm);
|
||||
} else {
|
||||
display.getMetrics(dm);
|
||||
}
|
||||
return dm;
|
||||
}
|
||||
|
||||
public static int getScreenDensity(Context context) {
|
||||
try {
|
||||
return (int) Math.round(context.getResources().getDisplayMetrics().density);
|
||||
@@ -635,7 +786,7 @@ public class SystemUtils {
|
||||
}
|
||||
|
||||
public static String getProductName() {
|
||||
return getProperty(Build.PRODUCT, Build.UNKNOWN);
|
||||
return getProperty("ro.product.name", Build.PRODUCT);
|
||||
}
|
||||
|
||||
public static String getProductModel() {
|
||||
@@ -682,7 +833,7 @@ public class SystemUtils {
|
||||
}
|
||||
|
||||
public static String getBootloader() {
|
||||
return getProperty(Build.BOOTLOADER, Build.UNKNOWN);
|
||||
return getProperty("ro.bootloader", Build.BOOTLOADER);
|
||||
}
|
||||
|
||||
public static String getBasebandVersion() {
|
||||
@@ -699,7 +850,7 @@ public class SystemUtils {
|
||||
|
||||
public static String getScreenSize(Context context) {
|
||||
try {
|
||||
android.util.DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
android.util.DisplayMetrics dm = getRealDisplayMetrics(context);
|
||||
double diagonal = Math.sqrt(Math.pow(dm.widthPixels / dm.xdpi, 2)
|
||||
+ Math.pow(dm.heightPixels / dm.ydpi, 2));
|
||||
return String.format(Locale.US, "%.1f", diagonal);
|
||||
@@ -710,7 +861,7 @@ public class SystemUtils {
|
||||
|
||||
public static double getScreenInch(Context context) {
|
||||
try {
|
||||
android.util.DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
android.util.DisplayMetrics dm = getRealDisplayMetrics(context);
|
||||
double diagonal = Math.sqrt(Math.pow(dm.widthPixels / dm.xdpi, 2)
|
||||
+ Math.pow(dm.heightPixels / dm.ydpi, 2));
|
||||
return Math.round(diagonal * 10.0) / 10.0;
|
||||
|
||||
Reference in New Issue
Block a user