Compare commits

...

57 Commits

Author SHA1 Message Date
高志龙 7ba14570c0 fix: 视频素材替换 2 days ago
高志龙 8d6e1fad53 fix: ci 3 days ago
高志龙 3cd384ba64 fix: ci 6 days ago
高志龙 09651bc87e fix: ci 1 week ago
高志龙 92aadd8f4e fix: 优化 1 week ago
高志龙 f602c39e36 fix: ci 1 week ago
高志龙 149931988f fix: webview优化 2 weeks ago
高志龙 dd27cb26b9 fix: 优化 2 months ago
高志龙 ee7f1893ba fix: ci 2 months ago
高志龙 b130a44d97 fix: ci 2 months ago
高志龙 e1a865ded9 fix: ci 2 months ago
高志龙 aac2db792b fix: ci 2 months ago
高志龙 bb0f5785af fix: 截图 2 months ago
高志龙 17cb8d7093 fix: ci 2 months ago
高志龙 fa1874a0e1 fix: ci 2 months ago
高志龙 84965bc937 fix: 修改socket断联重启时间 2 months ago
高志龙 108235443e fix: ci 2 months ago
高志龙 da06587620 fix: ci 3 months ago
高志龙 e3be3811da fix: ci 3 months ago
高志龙 7be4b31379 fix: 视频切换优化 3 months ago
高志龙 016c8c3560 fix: 视频优化 3 months ago
高志龙 2e889612dd fix: 视频播放优化 3 months ago
高志龙 4af826eaf0 fix: 视频优化 4 months ago
高志龙 f407f29a4a fix: ci 4 months ago
高志龙 8168e95450 fix: ci 4 months ago
高志龙 dcf5b77bc5 fix: 视频替换 4 months ago
高志龙 df906835c6 fix: 新春版本 4 months ago
高志龙 126b722af4 fix: ci 4 months ago
高志龙 d12e0ed9d9 fix: ci 4 months ago
高志龙 59e3ac1ca5 fix: ci 4 months ago
高志龙 d7efd91739 fix: ci 6 months ago
高志龙 e3a8cfcf6c fix: startTTS 6 months ago
高志龙 c89945e121 fix: ci 7 months ago
高志龙 438d7c214a fix: 视频更新 7 months ago
高志龙 3fd11aea11 fix: ci 7 months ago
高志龙 7a7dc7373d fix: ci 7 months ago
高志龙 da6ad42ab7 fix: ci 7 months ago
高志龙 34b8b7cb6c fix: socket连接报错修改 7 months ago
高志龙 e4a6a98c71 fix: webview bug 8 months ago
高志龙 56e1fb8799 fix: ci 8 months ago
高志龙 1494c62ab4 fix: ci 8 months ago
高志龙 39d4b27007 fix: ci 8 months ago
高志龙 f3ca4d6300 fix: 启动延时 8 months ago
高志龙 42b9523806 fix: 变装 8 months ago
高志龙 f40d416311 fix: ci 8 months ago
高志龙 b6d1f99b88 fix: ci 8 months ago
高志龙 c2c9e4ea01 fix: ci 8 months ago
高志龙 f3470778d1 fix: ci 8 months ago
高志龙 eea35a6dbc fix: ci 8 months ago
高志龙 6c76042f53 fix: ci 8 months ago
高志龙 54616ffc75 fix: 语音报错处理 8 months ago
高志龙 da756bd6db fix: 隐藏导航栏 8 months ago
高志龙 3c66674762 fix: init 8 months ago
高志龙 c914eea9ec fix: init 9 months ago
高志龙 51870a2a7f fix: ci 9 months ago
高志龙 e8586712e2 fix: ci 9 months ago
高志龙 a4026ec295 fix: ci 9 months ago
  1. 10
      .idea/deploymentTargetSelector.xml
  2. 7
      .idea/gradle.xml
  3. 10
      .idea/migrations.xml
  4. 3
      .idea/misc.xml
  5. 26
      app/build.gradle
  6. BIN
      app/libs/AndroidScreenCap.jar
  7. BIN
      app/libs/SparkChain.aar
  8. BIN
      app/release/app_andorid_V2_卓策iot分屏容器_V2.0.7.30.apk
  9. BIN
      app/release/app_andorid_V2_卓策iot分屏容器_V2.0.7.31.apk
  10. BIN
      app/release/app_andorid_V2_卓策iot分屏容器_V2.0.8.0.apk
  11. BIN
      app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.31.apk
  12. BIN
      app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.32.apk
  13. BIN
      app/release/app_andorid_V2_视美泰设备iot分屏容器_V2.0.7.33.apk
  14. 2
      app/release/output-metadata.json
  15. 91
      app/src/main/AndroidManifest.xml
  16. 2
      app/src/main/java/qianmu/container/activity/BaseActivity.java
  17. 80
      app/src/main/java/qianmu/container/activity/H5/H5Data.java
  18. 42
      app/src/main/java/qianmu/container/activity/H5/UpdateFileActivity.java
  19. 875
      app/src/main/java/qianmu/container/activity/H5/WebViewActivity.java
  20. 2
      app/src/main/java/qianmu/container/activity/program/ScreenSaverActivity.java
  21. 1
      app/src/main/java/qianmu/container/activity/program/ViewScreenSaver.java
  22. 6
      app/src/main/java/qianmu/container/app/Constant.java
  23. 105
      app/src/main/java/qianmu/container/app/MyApplication.java
  24. 1
      app/src/main/java/qianmu/container/data/PowerData.java
  25. 79
      app/src/main/java/qianmu/container/entity/TTSMessage.java
  26. 60
      app/src/main/java/qianmu/container/handler/ContainerHandler.java
  27. 9
      app/src/main/java/qianmu/container/http/retrofit/BaseService.java
  28. 161
      app/src/main/java/qianmu/container/mqtt/MQTTService.java
  29. 1
      app/src/main/java/qianmu/container/receiver/SystemEventReceiver.java
  30. 73
      app/src/main/java/qianmu/container/service/ContainerService.java
  31. 60
      app/src/main/java/qianmu/container/util/AudioPlay.java
  32. 235
      app/src/main/java/qianmu/container/util/Base64Util.java
  33. 86
      app/src/main/java/qianmu/container/util/DeviceUtil.java
  34. 59
      app/src/main/java/qianmu/container/util/FileUtil.java
  35. 103
      app/src/main/java/qianmu/container/util/SignUtil.java
  36. 16
      app/src/main/java/qianmu/container/util/SignWayUtil.java
  37. 179
      app/src/main/java/qianmu/container/util/TTSUtil.java
  38. 37
      app/src/main/res/layout/activity_test.xml
  39. 45
      app/src/main/res/layout/activity_webview.xml
  40. BIN
      app/src/main/res/raw/bg.mp4
  41. BIN
      app/src/main/res/raw/bg_old.mp4
  42. BIN
      app/src/main/res/raw/hello.mp4
  43. BIN
      app/src/main/res/raw/hello_old.mp4
  44. BIN
      app/src/main/res/raw/musice.mp3
  45. BIN
      app/src/main/res/raw/speek.mp4
  46. BIN
      app/src/main/res/raw/speek_old.mp4
  47. 3
      app/src/main/res/values/strings.xml
  48. 3
      app/src/main/res/values/styles.xml
  49. 10
      playerview/build.gradle
  50. 6
      playerview/src/androidTest/java/com/dl7/player/ExampleInstrumentedTest.java

10
.idea/deploymentTargetSelector.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

7
.idea/gradle.xml

@ -4,10 +4,8 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
@ -15,8 +13,7 @@
<option value="$PROJECT_DIR$/playerview" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>

10
.idea/migrations.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

3
.idea/misc.xml

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

26
app/build.gradle

@ -3,21 +3,19 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
buildFeatures {
dataBinding = true
}
dataBinding { enabled = true }
defaultConfig {
applicationId "qianmu.container"
minSdkVersion 22
minSdkVersion 26
targetSdkVersion 30
versionCode 6
versionName "V2.0.7.30"
versionName "V2.0.7.61"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
ndk { abiFilters "armeabi-v7a", "arm64-v8a" }
ndk { abiFilters "armeabi-v7a" }
javaCompileOptions {
annotationProcessorOptions {
@ -92,21 +90,23 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation files('libs\\ymeeting.jar')//亿
implementation project(path: ':playerview')
implementation files('libs\\Msc.jar')
implementation files('libs/SparkChain.aar')
implementation files('libs\\zckjAPI-2.2.jar')//
implementation files('libs\\jna-min.jar')
implementation files('libs\\toolbox_kit.jar')//
implementation files('libs\\shockman.jar')//
implementation files('libs/signway.jar') //
implementation files('libs\\signway.jar') //
implementation files('libs\\sdkapi.jar') //Bv-3588
implementation files('libs\\smdt.jar') //
implementation files('libs\\smdt.jar')//
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.lzy.net:okgo:3.0.4'
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
implementation ('com.lzy.net:okgo:3.0.4') {
exclude group: 'com.squareup.okhttp3' // OkGo OkHttp 3.8.1
}
implementation 'org.greenrobot:eventbus:3.1.1'
implementation 'com.alibaba:arouter-api:1.5.0'
implementation 'com.github.bumptech.glide:glide:4.9.0'
@ -133,8 +133,8 @@ dependencies {
implementation 'cn.hutool:hutool-all:5.8.26'
//
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.3'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
//
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'

BIN
app/libs/AndroidScreenCap.jar

Binary file not shown.

BIN
app/libs/SparkChain.aar

Binary file not shown.

BIN
app/release/app_andorid_V2_卓策iot分屏容器_V2.0.7.30.apk

Binary file not shown.

BIN
app/release/app_andorid_V2_亿晟3576iot分屏容器_V2.0.7.30.apk → app/release/app_andorid_V2_卓策iot分屏容器_V2.0.7.31.apk

Binary file not shown.

BIN
app/release/app-release.apk → app/release/app_andorid_V2_卓策iot分屏容器_V2.0.8.0.apk

Binary file not shown.

BIN
app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.31.apk

Binary file not shown.

BIN
app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.32.apk

Binary file not shown.

BIN
app/release/app_andorid_V2_视美泰设备iot分屏容器_V2.0.7.33.apk

Binary file not shown.

2
app/release/output-metadata.json

@ -11,7 +11,7 @@
"type": "SINGLE",
"filters": [],
"versionCode": 6,
"versionName": "V2.0.7.30",
"versionName": "V2.0.7.33",
"outputFile": "app-release.apk"
}
]

91
app/src/main/AndroidManifest.xml

@ -2,51 +2,35 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="qianmu.container">
<!--显示系统窗口 显示系统窗口-->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!--录音 录制声音通过手机或耳机的麦克-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!--开机自动允许 允许程序开机自动运行-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!--改变WiFi状态 改变WiFi状态-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--获取WiFi状态 获取当前WiFi接入的状态以及WLAN热点的信息-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--唤醒锁定 允许程序在手机屏幕关闭后后台进程仍然运行-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--写入外部存储 允许程序写入外部存储,如SD卡上写文件-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--读取外部存储 允许程序读取外部存储,如SD卡上读文件-->
<!-- 显示系统窗口 显示系统窗口 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 录音 录制声音通过手机或耳机的麦克 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- 开机自动允许 允许程序开机自动运行 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- 改变WiFi状态 改变WiFi状态 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- 获取WiFi状态 获取当前WiFi接入的状态以及WLAN热点的信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 唤醒锁定 允许程序在手机屏幕关闭后后台进程仍然运行 -->
<uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 写入外部存储 允许程序写入外部存储,如SD卡上写文件 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 读取外部存储 允许程序读取外部存储,如SD卡上读文件 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES"
<uses-permission
android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!--获取网络状态 获取网络信息状态,如当前的网络连接是否有效-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--访问网络 访问网络连接,可能产生GPRS流量-->
<uses-permission android:name="android.permission.INTERNET" />
<!---->
<uses-permission android:name="android.hardware.camera.autofocus" />
<!--连续广播 允许一个程序收到广播后快速收到下一个广播-->
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<!--拍照权限 允许访问摄像头进行拍照-->
<uses-permission android:name="android.permission.CAMERA" />
<!--读取电话状态 访问电话状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--读取外部存储 允许程序读取外部存储,如SD卡上读文件-->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!--获取任务信息 允许程序获取当前或最近运行的应用-->
<uses-permission android:name="android.permission.GET_TASKS" />
<!--对话框权限-->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <!-- 获取网络状态 获取网络信息状态,如当前的网络连接是否有效 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 访问网络 访问网络连接,可能产生GPRS流量 -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- -->
<uses-permission android:name="android.hardware.camera.autofocus" /> <!-- 连续广播 允许一个程序收到广播后快速收到下一个广播 -->
<uses-permission android:name="android.permission.BROADCAST_STICKY" /> <!-- 拍照权限 允许访问摄像头进行拍照 -->
<uses-permission android:name="android.permission.CAMERA" /> <!-- 读取电话状态 访问电话状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 读取外部存储 允许程序读取外部存储,如SD卡上读文件 -->
<uses-permission android:name="android.permission.GET_TASKS" /> <!-- 对话框权限 -->
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"
<uses-permission
android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.SET_TIME_ZONE"
<uses-permission
android:name="android.permission.SET_TIME_ZONE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.SET_TIME"
<uses-permission
android:name="android.permission.SET_TIME"
tools:ignore="ProtectedPermissions" />
<application
@ -55,9 +39,12 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:sharedUserId="android.uid.system"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:hardwareAccelerated="true"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme">
<provider
@ -77,41 +64,33 @@
android:screenOrientation="nosensor">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.program.ScreenSaverActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|navigation"
android:launchMode="singleTask"
android:screenOrientation="nosensor" />
<activity
android:name=".activity.device.DeviceInfoActivity"
android:launchMode="singleTask"
android:screenOrientation="nosensor"/>
android:screenOrientation="nosensor" />
<activity
android:name=".activity.H5.WebViewActivity"
android:launchMode="singleTask"
android:screenOrientation="nosensor"/>
<service android:name=".service.ContainerService" />
android:screenOrientation="nosensor" />
<service android:name=".service.ContainerService" />
<service android:name=".activity.H5.CoreService" />
<service android:name=".service.MusicService"/>
<service android:name=".service.MusicService" />
<service
android:name=".mqtt.MQTTService"
android:enabled="true"
android:exported="true"></service>
android:exported="true" />
<service android:name="org.eclipse.paho.android.service.MqttService" />
<service
android:name=".service.MessengerService"
android:exported="true">
@ -124,7 +103,6 @@
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
@ -132,7 +110,6 @@
<data android:scheme="file" />
</intent-filter>
</receiver>
</application>

2
app/src/main/java/qianmu/container/activity/BaseActivity.java

@ -273,7 +273,7 @@ public abstract class BaseActivity extends AppCompatActivity {
}
if(Constant.androidBoardType.equals("smt")){
MyApplication.getInstance().getSmdt().sys_setDaemonsActivity(this.getPackageName(),3600000,true);
MyApplication.getInstance().getSmdt().sys_setDaemonsActivity(this.getPackageName(),300000,true);
}
try {

80
app/src/main/java/qianmu/container/activity/H5/H5Data.java

@ -18,6 +18,7 @@ import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -44,6 +45,7 @@ import qianmu.container.util.AesUtil;
import qianmu.container.util.FileUtil;
import qianmu.container.util.GsonUtil;
import qianmu.container.util.LoggerUtil;
import qianmu.container.util.SignUtil;
import qianmu.container.util.StringUtil;
import retrofit2.Call;
import retrofit2.Callback;
@ -54,6 +56,7 @@ public class H5Data extends BaseData {
public static final String NAME = "H5_app_data";
public static final String H5_APP_VERSION = "H5_version";
public static final String INTERFACE_LIST = "interface_list";
public static final String AI_FILE_RESOURCE_LIST = "aiFileResource_list"; //AI资源文件
public static final String FILE_RESOURCE_LIST = "fileResource_list";//资源文件下载,图片,视频
public static final String MODEL_FILE_RESOURCE_LIST = "modelFileResource_list";//模型资源文件下载,图片,(水牌使用)
public static final String H5_URL = "h5_url"; // 除导视外其他url
@ -105,6 +108,30 @@ public class H5Data extends BaseData {
saveDataJson(NAME, MODEL_FILE_RESOURCE_LIST, dataJson);
}
/**
* 保存AI文件资源列表
* */
public static void saveAIResourceFileList(Object data) {
String dataJson;
if (data instanceof String) dataJson = (String) data;
else dataJson = new Gson().toJson(data);
saveDataJson(NAME, AI_FILE_RESOURCE_LIST, dataJson);
}
/**
* 获取模型文件资源列表
* */
public static List<ResourceFileBean> getAiResourceFileList() {
try {
String dataJson = getDataJson(NAME, AI_FILE_RESOURCE_LIST);
return new Gson().fromJson(dataJson, new TypeToken<List<ResourceFileBean>>() {
}.getType());
} catch (Throwable t) {
LoggerUtil.e("getAIResourceFileList", StringUtil.getThrowableStr(t));
}
return new ArrayList<>();
}
/**
* 获取文件资源列表
* */
@ -292,6 +319,51 @@ public class H5Data extends BaseData {
});
}
// 获取AI离线文件
public static void queryAiServeList(QueryPreparedListener preparedListener, QueryFinishListener finishListener , Map<String, String> bigFiles ) {
if (preparedListener != null) preparedListener.onPrepared();
String mallCode = FloorData.getMallCode();
long timeStrap = System.currentTimeMillis();
String regKey = DeviceData.getDeviceInfo(DeviceData.HINT_REG_KEY);
Map<String, String> headers = new HashMap<>();
headers.put("projectcode", mallCode);
headers.put("timeStrap", String.valueOf(timeStrap));
headers.put("sign", SignUtil.buildSk(regKey, mallCode, timeStrap));
RetrofitUtil.getBaseService().getAiFileResource(headers,mallCode).enqueue(new Callback<Resp>() {
@Override
public void onResponse(Call<Resp> call, Response<Resp> response) {
try {
if (StringUtil.respSuccess(response.body())) {
String dataJson = new Gson().toJson(response.body().getData());
if(dataJson.contains("capacity")){
Object data = response.body().getData();
saveAIResourceFileList(data);
}else {
//解密
dataJson= AesUtil.decrypt((String.valueOf(response.body().getData())));
saveAIResourceFileList(dataJson);
}
for(ResourceFileBean fileBean:getAiResourceFileList()){
bigFiles.put(fileBean.getUrl(), StringUtil.strSplice("dist", "/static/offline/", fileBean.getUrl()));
}
}
} catch (Throwable t) {
LoggerUtil.e("getAiFileResource", StringUtil.getThrowableStr(t));
}
if (finishListener != null) finishListener.onFinish();
}
@Override
public void onFailure(Call<Resp> call, Throwable t) {
if (finishListener != null) finishListener.onFinish();
}
});
}
//GET方式获取离线数据
public static void queryOfflineDataByInterfaceToGet(String url, String jsonData, String fileName, Map<String, String> bigFiles , QueryPreparedListener preparedListener, QueryFinishListener finishListener) {
if (preparedListener != null) preparedListener.onPrepared();
@ -312,15 +384,15 @@ public class H5Data extends BaseData {
String deviceCode = DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_CODE);
url = url +"&"+"code="+deviceCode;
}
if(!url.startsWith("http")){
url = StringUtil.strSplice(Constant.getBaseAddress(), url);
}
String finalUrl = url;
client.get(url, new AsyncHttpResponseHandler() {
client.get(finalUrl, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
try {
String response = new String(responseBody).replace("\\\\", "/");
// Log.d("url", finalUrl);
// Log.d("response", response);
//获取数据成功时 才解析解析素材url并更新离线文件
Resp resp = new Gson().fromJson(response, new TypeToken<Resp>() {}.getType());

42
app/src/main/java/qianmu/container/activity/H5/UpdateFileActivity.java

@ -1,6 +1,7 @@
package qianmu.container.activity.H5;
import android.app.smdt.SmdtManagerNew;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
@ -16,6 +17,8 @@ import androidx.databinding.DataBindingUtil;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import com.iflytek.sparkchain.core.SparkChain;
import com.iflytek.sparkchain.core.SparkChainConfig;
import com.sdkapi.api.SdkApi;
import java.io.File;
@ -173,8 +176,8 @@ public class UpdateFileActivity extends BaseActivity {
H5Data.queryFileResources( () -> totalQueryCount++, () -> queryResponseCount++ ,bigFiles);
getOfflineDataByInterface();
}
H5Data.queryAiServeList( () -> totalQueryCount++, () -> queryResponseCount++ ,bigFiles);
if("指路机".equals(deviceType)){
DeviceData.getBackgroundMusic( () -> totalQueryCount++, () -> queryResponseCount++ ,bigFiles);
@ -252,18 +255,41 @@ public class UpdateFileActivity extends BaseActivity {
//新版欣威视通初始化
SdkApi.newInstance(this);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if(!Environment.isExternalStorageManager()){
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.setData(Uri.parse("package:" + this.getPackageName())); // 设置要申请权限的应用包名
startActivity(intent); // 启动活动以请求用户授权
return;
if("kdxf".equals(Constant.TTSFac)){
Log.d("MainActivity: ","initKDXFSDK");
// 初始化SDK,Appid等信息在清单中配置
SparkChainConfig sparkChainConfig = SparkChainConfig.builder();
sparkChainConfig.appID(getResources().getString(R.string.appid))
.apiKey(getResources().getString(R.string.apikey))
.apiSecret(getResources().getString(R.string.apiSecret))//应用申请的appid三元组
.logLevel(666);
int ret = SparkChain.getInst().init(getApplicationContext(),sparkChainConfig);
String result;
if(ret == 0){
result = "SDK初始化成功,请选择相应的功能点击体验。";
}else{
result = "SDK初始化失败,错误码:" + ret;
}
Log.e("MainActivity: ",result);
}
try{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if(!Environment.isExternalStorageManager()){
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.setData(Uri.parse("package:" + this.getPackageName())); // 设置要申请权限的应用包名
startActivity(intent); // 启动活动以请求用户授权
return;
}
}
}catch (ActivityNotFoundException e){
}
//设置开机自启应用
if(Constant.androidBoardType.equals("smt")){
MyApplication.getInstance().getSmdt().sys_setSystemBootApp(MyApplication.getInstance().getPackageName());
MyApplication.getInstance().getSmdt().sys_setDaemonsActivity(MyApplication.getInstance().getPackageName(),2000,true);
MyApplication.getInstance().getSmdt().sys_setDaemonsActivity(MyApplication.getInstance().getPackageName(),30000,true);
}
}

875
app/src/main/java/qianmu/container/activity/H5/WebViewActivity.java

File diff suppressed because it is too large

2
app/src/main/java/qianmu/container/activity/program/ScreenSaverActivity.java

@ -183,7 +183,7 @@ public class ScreenSaverActivity extends BaseActivity {
////////////////// webSocket
Log.e("WebSocket: ", "init");
connectionWebSocket("localhost",50002);
// connectionWebSocket("localhost",50002);
}
public void connectionWebSocket(String hostName, int port) {

1
app/src/main/java/qianmu/container/activity/program/ViewScreenSaver.java

@ -45,7 +45,6 @@ import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import org.greenrobot.eventbus.EventBus;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileNotFoundException;

6
app/src/main/java/qianmu/container/app/Constant.java

@ -22,7 +22,7 @@ public class Constant {
public static String screenType = "HDMI"; // 欣威视通3399设备为假关机 HDMI连接:可以用来判断是否为关机状态 LVDS连接:只能用定时关机时间来判断
public static boolean newGuide = false; // 指路机类型,true:新版指路机 false:老板指路机(流花)
public static String mqttState = ""; // 屏幕连接方式
public static String androidBoardType = ""; //设备板子型号 无固定版
// public static String androidBoardType = ""; //设备板子型号 无固定版
// public static String androidBoardType = "ys"; // 设备板子型号 ys(亿晟) 北京颐堤港定制touch
// public static String androidBoardType = "xwst"; //设备板子型号 xwst(欣威视通3399)
// public static String androidBoardType = "xwst2"; //设备板子型号 xwst2(欣威视通3588、T982、3576)
@ -31,8 +31,10 @@ public class Constant {
// public static String androidBoardType = "nova"; //设备板子型号 诺瓦盒子 华贸LED
// public static String androidBoardType = "huidu"; //设备板子型号 huidu(灰度主板) 罗湖寻车机
// public static String androidBoardType = "bv"; //设备板子型号 Bv-3588M
// public static String androidBoardType = "smt"; //设备板子型号 视美泰
public static String androidBoardType = "smt"; //设备板子型号 视美泰
public static String TTSFac = "sbc"; // 语音识别厂家 kdxf--科大讯飞 sbc-思必驰
public static final String VOID_STOP = "void_stop";//
public static String whoActivity = ""; // 哪个activity页面
// 本地缓存地址
public static final String CACHE_PATH = StringUtil.strSplice(Environment.getExternalStorageDirectory().getPath(),

105
app/src/main/java/qianmu/container/app/MyApplication.java

@ -16,6 +16,7 @@ import com.lzy.okgo.OkGo;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@ -38,8 +39,11 @@ import qianmu.container.socket.manager.SocketServerManager;
import qianmu.container.util.DeviceUtil;
import qianmu.container.util.LoggerUtil;
import qianmu.container.util.SSLSocketClient;
import qianmu.container.util.SignWayUtil;
import qianmu.container.util.StringUtil;
import static qianmu.container.util.LoggerUtil.SAVE_LOG_DIR_PATH;
@SuppressWarnings("All")
public class MyApplication extends Application {
@ -67,6 +71,11 @@ public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
myApplication = this;
try {
Thread.sleep(13000);
} catch (InterruptedException e) {
e.printStackTrace();
}
initARouter();
initOkGo();
SocketServerManager.startSocketServer();
@ -117,20 +126,7 @@ public class MyApplication extends Application {
private void initOkGo() {
try {
int currentApiVersion = android.os.Build.VERSION.SDK_INT;
OkHttpClient client;
if (currentApiVersion <= 32) {
// 当前系统版本是Android 12
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.readTimeout(5, TimeUnit.SECONDS);
builder.writeTimeout(5, TimeUnit.SECONDS);
builder.connectTimeout(5, TimeUnit.SECONDS);
builder.sslSocketFactory(SSLSocketClient.getSSLSocketFactory());// 过滤https证书
builder.hostnameVerifier(SSLSocketClient.getHostnameVerifier());
client = builder.build();
} else {
// 当前系统版本是Android 14
client = createOkHttpClient(this);
}
OkHttpClient client = createOkHttpClient(this);
OkGo.getInstance().init(this).setOkHttpClient(client).setRetryCount(0);
} catch (Throwable t) {
LoggerUtil.e("initOkGo", StringUtil.getThrowableStr(t));
@ -139,30 +135,26 @@ public class MyApplication extends Application {
public OkHttpClient createOkHttpClient(Context context) {
try {
// 1. 创建信任管理器(这里示例为信任所有证书,生产环境需谨慎)
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
// 2. 初始化 SSLContext
// 获取系统默认信任管理器
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
// 初始化 SSL 上下文
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, null);
// 3. 用自定义的 SSLContext 创建 SSLSocketFactory
javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// 4. 配置 OkHttpClient
// 构建 OkHttpClient(3.x 版本同样需要显式传入 trustManager)
return new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager) // 同时传入 TrustManager
.sslSocketFactory(sslContext.getSocketFactory(), trustManager) // 关键
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build();
} catch (Exception e) {
throw new RuntimeException(e);
throw new RuntimeException("OkHttp 初始化失败", e);
}
}
@ -183,24 +175,38 @@ public class MyApplication extends Application {
String errorLog = StringUtil.strSplice(
MyApplication.getInstance().dateTimeFormat.format(new Date(timeMillis)), ":\n",
throwable.getMessage(), "\n", sw.toString());
LoggerUtil.e("errorLog", errorLog);
restartApp();
Intent intent = new Intent(Constant.ACTION_APP_CRASH);
intent.putExtra(Constant.PACKAGE_NAME, DeviceUtil.getPackageName());
sendStickyBroadcast(intent);
sendBroadcast(new Intent(Constant.ACTION_EXIT));
try {
PackageManager packageManager = getPackageManager();
Intent appIntent = packageManager.getLaunchIntentForPackage(Constant.APP_CRASH_PACKAGE_NAME);
startActivity(appIntent);
} catch (Throwable t) {
LoggerUtil.e("崩溃自启失败", StringUtil.getThrowableStr(t));
restartApp();
LoggerUtil.e("APP崩溃", errorLog);
if (isSystemExceptionInternal(throwable)) {
try {
Thread.sleep(5000);
SignWayUtil.reboot();
} catch (InterruptedException e) {
e.printStackTrace();
}
return;
}
restartApp();
});
}
private boolean isSystemExceptionInternal(Throwable throwable) {
String className = throwable.getClass().getName();
String message = throwable.getMessage();
// 检查常见的系统异常
return className.contains("DeadSystemException") ||
className.contains("DeadObjectException") ||
className.contains("RemoteException") ||
className.contains("TransactionTooLargeException") ||
className.contains("NetworkOnMainThreadException") ||
className.contains("BadParcelableException") ||
className.contains("NullPointerException") &&
(message != null && message.contains("on a null object reference")) ||
className.contains("IllegalStateException") &&
(message != null && (message.contains("Fragment not attached") ||
message.contains("Activity has been destroyed")));
}
/**
* 重启软件
*/
@ -215,11 +221,6 @@ public class MyApplication extends Application {
// 开启背景音乐
stopService(new Intent(this, MusicService.class));// 背景音乐
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ProcessPhoenix.triggerRebirth(this);
}

1
app/src/main/java/qianmu/container/data/PowerData.java

@ -161,7 +161,6 @@ public class PowerData extends BaseData {
LoggerUtil.e("pingNet()", "开机检测网络异常,重启设备");
DeviceData.saveDeviceInfo((DeviceData.DEVICE_RESTART_TIME),format);
SignWayUtil.reboot();
}
} );
}

79
app/src/main/java/qianmu/container/entity/TTSMessage.java

@ -0,0 +1,79 @@
package qianmu.container.entity;
public class TTSMessage {
String jsonrpc;
String method;
Params params;
public String getJsonrpc() {
return jsonrpc;
}
public void setJsonrpc(String jsonrpc) {
this.jsonrpc = jsonrpc;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Params getParams() {
return params;
}
public void setParams(Params params) {
this.params = params;
}
public static class Params {
String text;
String status;
String ttsId;
String sessionId;
String network;
public String getNetwork() {
return network;
}
public void setNetwork(String network) {
this.network = network;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public String getTtsId() {
return ttsId;
}
public void setTtsId(String ttsId) {
this.ttsId = ttsId;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
}

60
app/src/main/java/qianmu/container/handler/ContainerHandler.java

@ -66,13 +66,13 @@ public class ContainerHandler extends Handler {
public static final int CLOSE_LOCAL_SOCKET = 4; //关闭本地socket
public static final int START_SOCKET_SERVER = 5; //启动socket服务
public static final int STOP_SOCKET_SERVER = 6; //停止socket服务
public static final int UPDATE_APP = 120 * 1000; //app更新包时间间隔
public static final int UPDATE_APP = 180 * 1000; //app更新包时间间隔
public static final int MQTT_ALIVE = 7; //app更新包时间间隔
public static final int GET_TIME_TAMP = 8; //获取时间戳
public static final int INIT_NOVA = 9; //获取时间戳
public static final int INIT_JXB = 10; //设置机械臂
public static final int INIT_JXB2 = 11; //设置机械臂
public long goNavTime =0;
public int goMemoryTime =0;
private WeakReference<ContainerService> weakReference;
@ -83,7 +83,7 @@ public class ContainerHandler extends Handler {
sendEmptyMessageDelayed(DELAY_TIME, DELAY_TIME);
sendEmptyMessageDelayed(UPDATE_APP, UPDATE_APP);//app更新
sendEmptyMessageDelayed(GET_TIME_TAMP, 100000);//获取时间戳
sendEmptyMessageDelayed(INIT_NOVA,1000);//获取时间戳
sendEmptyMessageDelayed(INIT_NOVA,60000);//获取时间戳
sendEmptyMessageDelayed(INIT_JXB,182000);//设置机械臂
sendEmptyMessageDelayed(INIT_JXB2,186000);//设置机械臂
}
@ -128,9 +128,9 @@ public class ContainerHandler extends Handler {
public void onSuccess() {
//检查,MQTT状态
mqttState();
sendEmptyMessageDelayed(MQTT_ALIVE,15000);
sendEmptyMessageDelayed(MQTT_ALIVE,35000);
sendEmptyMessageDelayed(MQTT_ALIVE,55000);
removeMessages(MQTT_ALIVE);
sendEmptyMessageDelayed(MQTT_ALIVE,20000);
sendEmptyMessageDelayed(MQTT_ALIVE,40000);
Constant.networkState=true;
}
},new QueryErrorListener() {
@ -139,8 +139,11 @@ public class ContainerHandler extends Handler {
Constant.networkState = false;
}
} );
getMemory();
if(goMemoryTime>5){
goMemoryTime = 0;
getMemory();
}
goMemoryTime++;
// watchDog();
getCoreServiceState();
// DeviceData.getPrimaryMachine(null, this::updateClientStateByIP);
@ -192,15 +195,6 @@ public class ContainerHandler extends Handler {
// LoggerUtil.e("ContainerHandler","cpu使用率:"+cpuUsage+"%");
// }
//
if(totalPss/1024>1000 && DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_TYPE).equals("导视") && !Constant.whoActivity.equals(Constant.ROUTE_WEB_VIEW)){
//内存超过了1G会出现卡顿
long currentTime = System.currentTimeMillis();
if(currentTime-goNavTime>360000){
LoggerUtil.e("getMemory()","内存超过1000 进入导视释放内存");
ARouter.getInstance().build(Constant.ROUTE_WEB_VIEW).withBoolean(Constant.KEY_LOAD_H5_URL, true).navigation();
goNavTime = currentTime;
}
}
if(totalPss/1024>1400){
//内存超过了1G会出现卡顿,内存溢出问题。重启设备。
LoggerUtil.e("getMemory()","内存溢出重启软件");
@ -340,7 +334,9 @@ public class ContainerHandler extends Handler {
//30分钟定时定时拉取更新APP
private void updateApp(){
sendEmptyMessageDelayed(UPDATE_APP, 1800*1000);//app更新
weakReference.get().appUpdate();
ContainerService service = weakReference.get();
if(service == null) return;
service.appUpdate();
//同屏接口
DeviceData.getPrimaryMachine(null, this::updateClientStateByIP);
}
@ -349,7 +345,9 @@ public class ContainerHandler extends Handler {
* 获取时间戳设置系统时间
* */
private void setSystemTime(){
weakReference.get().getCurrentTimestamp();
ContainerService service = weakReference.get();
if(service == null) return;
service.getCurrentTimestamp();
if("指路机".equals(DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_TYPE))){
//开启背景音乐
@ -358,18 +356,18 @@ public class ContainerHandler extends Handler {
}
private void delayTime() {
try {
sendEmptyMessageDelayed(DELAY_TIME, DELAY_TIME);
// weakReference.get().showSplashActivity();//改为前端通知容器是否进入屏保
//每5秒钟发送一次socket心跳
String second = MyApplication.getInstance().secondFormat.format(System.currentTimeMillis());
if (Integer.valueOf(second) % 5 == 0){
weakReference.get().detectionAppState();
LocSocCliManager.sendHeartBeatToServer();
}
} catch (Throwable t) {
LoggerUtil.e("delayTime", StringUtil.getThrowableStr(t));
}
// try {
// sendEmptyMessageDelayed(DELAY_TIME, DELAY_TIME);
// // weakReference.get().showSplashActivity();//改为前端通知容器是否进入屏保
// //每5秒钟发送一次socket心跳
// String second = MyApplication.getInstance().secondFormat.format(System.currentTimeMillis());
// if (Integer.valueOf(second) % 5 == 0){
// weakReference.get().detectionAppState();
// LocSocCliManager.sendHeartBeatToServer();
// }
// } catch (Throwable t) {
// LoggerUtil.e("delayTime", StringUtil.getThrowableStr(t));
// }
}
/**

9
app/src/main/java/qianmu/container/http/retrofit/BaseService.java

@ -2,6 +2,7 @@ package qianmu.container.http.retrofit;
import java.io.File;
import java.util.Map;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
@ -12,6 +13,7 @@ import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.HeaderMap;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
@ -141,6 +143,13 @@ public interface BaseService {
@GET("api/data/v1/web/getFileResource")
Call<Resp> getFileResourceList2(@Query("projectCode") String code);
/**
* 获取资源文件(AI服务)
* @return
*/
@GET("api/aimgr/v1/web/file-resources")
Call<Resp> getAiFileResource(@HeaderMap Map<String, String> headers, @Query("projectCode") String code);
/**
* 获取模型资源文件列表(水牌)
*

161
app/src/main/java/qianmu/container/mqtt/MQTTService.java

@ -51,6 +51,7 @@ import java.security.KeyManagementException;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@ -62,7 +63,9 @@ import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
@ -91,6 +94,7 @@ import qianmu.container.util.BitmapUtil;
import qianmu.container.util.DeviceUtil;
import qianmu.container.util.FileUtil;
import qianmu.container.util.LoggerUtil;
import qianmu.container.util.RootCmdUtil;
import qianmu.container.util.SignWayUtil;
import qianmu.container.util.StringUtil;
import retrofit2.Call;
@ -140,7 +144,7 @@ public class MQTTService extends Service {
userName= DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_CODE);
if(Constant.tywx){
passWord= AesUtil.md5(DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_MAC, SignWayUtil.getEthMacAddress()));
Log.e("MQTTService","passWord:"+passWord);
LoggerUtil.e("MQTTService","passWord:"+passWord);
}else {
passWord= MqttData.getMqttToken().getPassword();
}
@ -182,8 +186,9 @@ public class MQTTService extends Service {
// 用户名
conOpt.setUserName(userName);
// 密码
conOpt.setPassword(passWord.toCharArray()); //将字符串转换为字符串数组
if(!StringUtil.isEmpty(passWord)){
conOpt.setPassword(passWord.toCharArray()); //将字符串转换为字符串数组
}
// conOpt.setAutomaticReconnect(true);
// last will message
@ -231,11 +236,11 @@ public class MQTTService extends Service {
sendOffline();
disconnectMqtt();
stopSelf();
// try {
// client.disconnect();
// } catch (MqttException e) {
// e.printStackTrace();
// }
try {
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
EventBus.getDefault().unregister(this);
super.onDestroy();
}
@ -252,8 +257,8 @@ public class MQTTService extends Service {
LoggerUtil.e(TAG,"MQTT尝试重连");
client.connect(conOpt, null, iMqttActionListener);
}
} catch (MqttException e) {
e.printStackTrace();
} catch (Exception e) {
LoggerUtil.e(TAG, "MQTT连接异常: " + e.getMessage());
}
}
@ -265,6 +270,10 @@ public class MQTTService extends Service {
public void onSuccess(IMqttToken arg0) {
LoggerUtil.e(TAG, "连接成功 ");
isConnected = true;
try {
// 先取消旧订阅(防止重复累积)
client.unsubscribe(myTopic);
} catch (MqttException e) { /* ignore */ }
try {
// 订阅myTopic话题
client.subscribe(myTopic,2);
@ -455,6 +464,10 @@ public class MQTTService extends Service {
CloseMqttBean closeMqttBean =new Gson().fromJson(msg, new TypeToken<CloseMqttBean>() {
}.getType());
if(closeMqttBean == null || closeMqttBean.getType() == null){
LoggerUtil.e(TAG,"sendCommand: type为空,忽略消息:"+msg);
return;
}
if(closeMqttBean.getType().equals("app-update")){
//APP下发
appUpdate(closeMqttBean);
@ -476,6 +489,7 @@ public class MQTTService extends Service {
SignWayUtil.shutDown();
}else if(closeMqttBean.getType().equals("device-time-update")){
//定时开关机
if(closeMqttBean.getData() == null || closeMqttBean.getData().getTime() == null) return;
PowerData.savePowerList(closeMqttBean.getData().getTime());
}else if(closeMqttBean.getType().equals("device-time-clear")){
@ -510,6 +524,7 @@ public class MQTTService extends Service {
}
}else if(closeMqttBean.getType().equals("device-edit")){
//设备信息编辑
if(closeMqttBean.getData() == null || closeMqttBean.getData().getDevice() == null) return;
MqttDataBean.deviceData device = closeMqttBean.getData().getDevice();
DeviceData.saveDeviceName(device.getName());
DeviceData.saveDeviceInfo(DeviceData.HINT_DEVICE_TOUCH, String.valueOf(device.getTouch()));//设备触摸
@ -523,7 +538,6 @@ public class MQTTService extends Service {
DeviceData.saveDeviceInfo(DeviceData.FLOOR_NAME, device.getFloor());//楼层名称
if(device.getFloorCode()!=null){
DeviceData.saveDeviceInfo(DeviceData.FLOOR_CODE, device.getFloorCode());//楼层code
}
FloorData.getDeviceOptionsNew(DeviceData.getDeviceInfo(DeviceData.HINT_REG_KEY),null, null);
}
@ -632,71 +646,82 @@ public class MQTTService extends Service {
/**
* 截屏
* */
public static void screenShot(long time) {
private static final ExecutorService SCREEN_SHOT_EXECUTOR = Executors.newSingleThreadExecutor();
if(Constant.androidBoardType.equals("nova")){
MessageEvent messageEvent = new MessageEvent(Constant.NOVA_SCREEN_SHOT);
messageEvent.setData(""+time);
EventBus.getDefault().post(messageEvent);
return;
}
String path = StringUtil.strSplice(BitmapUtil.SAVE_SCREEN_SHOT_PATH, "/screenShot.png");
File file = new File(path);
File parent = file.getParentFile();
if (!parent.exists()) parent.mkdirs();
if(SignWayUtil.getgetAndroidModle().equals("t982")){
//亿晟主板t982特殊处理上传
boolean b = SignWayUtil.ysTakeScreenshot(path);
if(!b){
return;
}
Executors.newSingleThreadExecutor().execute(() -> {
try {
uploadScreenShot(path,DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_CODE),String.valueOf(time));
} catch (Exception e) {
e.printStackTrace();
}
});
return;
}
String cmd = "screencap -p " + path;
Executors.newSingleThreadExecutor().execute(() -> {
public static void screenShot(long time) {
SCREEN_SHOT_EXECUTOR.submit(() -> {
try {
Process process = Runtime.getRuntime().exec("su");//不同的设备权限不一样
PrintWriter pw = new PrintWriter(process.getOutputStream());
pw.println(cmd);
pw.flush();
pw.println("exit");
pw.flush();
try {
process.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pw.close();
process.destroy();
if(!new File(path).exists()){
LoggerUtil.e("screenShot","截屏失败");
if (Constant.androidBoardType.equals("nova")) {
MessageEvent messageEvent = new MessageEvent(Constant.NOVA_SCREEN_SHOT);
messageEvent.setData("" + time);
EventBus.getDefault().post(messageEvent);
return;
}
uploadScreenShot(path,DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_CODE),String.valueOf(time));
} catch (IOException e) {
e.printStackTrace();
String path = StringUtil.strSplice(BitmapUtil.SAVE_SCREEN_SHOT_PATH, "/screenShot.png");
File file = new File(path);
File parent = file.getParentFile();
if (!parent.exists()) parent.mkdirs();
if (file.exists()) file.delete();
boolean shotSuccess = false;
// 亿晟主板
if (SignWayUtil.getgetAndroidModle().equals("t982")) {
shotSuccess = SignWayUtil.ysTakeScreenshot(path);
} else if (!"".equals(Constant.androidBoardType)) {
SignWayUtil.takeScreenshot(path);
int retryCount = 0;
final int MAX_RETRY = 16;
final long SLEEP_MS = 1000;
long lastSize = -1;
while (retryCount < MAX_RETRY) {
File f = new File(path);
if (f.exists()) {
long currentSize = f.length();
if (currentSize > 1024) {
if (currentSize == lastSize) {
LoggerUtil.e("screenShot", "截屏完成");
shotSuccess = true;
break;
}
}
lastSize = currentSize;
}
retryCount++;
try {
Thread.sleep(SLEEP_MS);
} catch (InterruptedException e) {
break;
}
}
} else {
LoggerUtil.e("screenShot", "root截屏");
String[] cmd = {"su", "-c", "screencap -p " + path};
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
while ((line = errorReader.readLine()) != null) {
LoggerUtil.e("screenShot", "error: " + line);
}
boolean finished = process.waitFor(3, TimeUnit.SECONDS);
if (!finished) {
process.destroyForcibly();
}
shotSuccess = new File(path).exists();
}
// 上传
if (shotSuccess) {
LoggerUtil.e("screenShot", "开始上传");
uploadScreenShot(path, DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_CODE), String.valueOf(time));
} else {
LoggerUtil.e("screenShot", "截屏失败");
}
} catch (Exception e) {
LoggerUtil.e("screenShot", "截屏异常:" + e.getMessage());
}
});
}
//上传截屏
public static void uploadScreenShot(String filePath,String code,String timestamp) {
File file = new File(filePath);
if (!file.exists()||code.isEmpty()) return;
if(SignWayUtil.getgetAndroidModle().equals("t982")){
@ -721,7 +746,6 @@ public class MQTTService extends Service {
LoggerUtil.e("uploadScreenShot", StringUtil.getThrowableStr(t));
}
});
}
/**
@ -731,6 +755,7 @@ public class MQTTService extends Service {
final String localPath = StringUtil.strSplice(Constant.CACHE_PATH, "update/", appName);
FileUtil.downloadFile(url, localPath, () -> {
isDownloadFile = false;
LoggerUtil.e("uploadApp", "APP下载完成");
AppUtil.installApp(localPath, DeviceUtil.getPackageName(), DeviceUtil.getPackageName(), true);
});
}
@ -745,7 +770,7 @@ public class MQTTService extends Service {
try {
SSLContext sc = SSLContext.getInstance("SSL");
try {
sc.init(null,trustAllCerts,null);
sc.init(null,trustAllCerts, new SecureRandom());
SSLSocketFactory factory = sc.getSocketFactory();
conOpt.setSocketFactory(factory);
} catch (KeyManagementException e) {

1
app/src/main/java/qianmu/container/receiver/SystemEventReceiver.java

@ -45,4 +45,5 @@ public class SystemEventReceiver extends BroadcastReceiver {
}
}
}

73
app/src/main/java/qianmu/container/service/ContainerService.java

@ -89,6 +89,7 @@ public class ContainerService extends Service {
initFirstTime();
initTempTime();
EventBus.getDefault().register(this);
LoggerUtil.e(TAG,"启动ContainerService");
handler = new ContainerHandler(this);
}
@ -154,7 +155,7 @@ public class ContainerService extends Service {
try {
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = am.getRunningAppProcesses();
if (appProcesses == null) return false;
if (appProcesses == null || appProcesses.isEmpty()) return false;
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (!appProcess.processName.equals(DeviceUtil.getPackageName())) continue;
if (appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
@ -172,32 +173,56 @@ public class ContainerService extends Service {
* 检测应用状态 如果在后台 唤醒到前台
*/
public void detectionAppState() {
final ActivityManager manager = (ActivityManager) MyApplication.getInstance().getSystemService(Context.ACTIVITY_SERVICE);
// 获得手机进程列表
List<ActivityManager.RunningAppProcessInfo> infoList = manager.getRunningAppProcesses();
String packageName = DeviceUtil.getPackageName();
for (ActivityManager.RunningAppProcessInfo info : infoList) {
if (packageName.equals(info.processName)
|| "com.android.packageinstaller".equals(info.processName)
|| "com.google.android.packageinstaller".equals(info.processName)
|| "com.frogshealth.qianmu".equals(info.processName)
|| "com.tencent.wmpf".equals(info.processName)) {
if (info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return;
try {
ActivityManager manager =(ActivityManager) MyApplication.getInstance().getSystemService(Context.ACTIVITY_SERVICE);
if (manager == null) {
LoggerUtil.e("detectionAppState","ActivityManager is null");
return;
}
// 获取运行中的进程
List<ActivityManager.RunningAppProcessInfo> infoList;
try {
infoList = manager.getRunningAppProcesses();
} catch (Exception e) {
LoggerUtil.e("detectionAppState", "getRunningAppProcesses error:" + e);
return;
}
if (infoList == null || infoList.isEmpty()) {
LoggerUtil.e("detectionAppState", "RunningAppProcesses is null");
return;
}
String packageName = DeviceUtil.getPackageName();
for (ActivityManager.RunningAppProcessInfo info : infoList) {
if (info == null) {
continue;
}
String processName = info.processName;
if (packageName.equals(processName)
|| "com.android.packageinstaller".equals(processName)
|| "com.google.android.packageinstaller".equals(processName)
|| "com.frogshealth.qianmu".equals(processName)
|| "com.tencent.wmpf".equals(processName)) {
if (info.importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
return;
}
}
}
LoggerUtil.e("detectionAppState", "检测应用被退到后台,重新唤醒到前台");
String deviceType = DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_TYPE);
if ("信发".equals(deviceType) || "双面屏".equals(deviceType)) {
Intent intent = new Intent( MyApplication.getInstance(), ScreenSaverActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApplication.getInstance().startActivity(intent);
} else {
LoggerUtil.e("detectionAppState", "跳转到导视");
ARouter.getInstance()
.build(Constant.ROUTE_WEB_VIEW)
.withBoolean(Constant.KEY_LOAD_H5_URL, true)
.navigation();
}
} catch (Exception e) {
LoggerUtil.e("detectionAppState","error:" + Log.getStackTraceString(e));
}
LoggerUtil.e("detectionAppState","检测应用被退到后台,重新唤醒到前台");
if("信发".equals( DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_TYPE))||"双面屏".equals( DeviceData.getDeviceInfo(DeviceData.HINT_DEVICE_TYPE))){
//信发
Intent intent = new Intent(MyApplication.getInstance(), ScreenSaverActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApplication.getInstance().startActivity(intent);
}else {
LoggerUtil.e("detectionAppState","跳转到导视");
ARouter.getInstance().build(Constant.ROUTE_WEB_VIEW).withBoolean(Constant.KEY_LOAD_H5_URL, true).navigation();
}
}
/**

60
app/src/main/java/qianmu/container/util/AudioPlay.java

@ -0,0 +1,60 @@
package qianmu.container.util;
import android.media.AudioAttributes;
import android.media.MediaPlayer;
import java.io.IOException;
public class AudioPlay {
private static volatile MediaPlayer mediaPlayer;
public static void startPlay(String url){
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
try {
mediaPlayer = new MediaPlayer();
// 设置音频属性(需在 setDataSource 前调用)
AudioAttributes attributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build();
mediaPlayer.setAudioAttributes(attributes);
// 设置数据源(确保路径正确,且有读取权限)
mediaPlayer.setDataSource(url);
// 异步准备(避免阻塞主线程)
mediaPlayer.prepareAsync();
mediaPlayer.setVolume(1.0f, 1.0f);
mediaPlayer.setOnPreparedListener(mp -> {
// 准备完成后才能播放
mp.start();
});
// 监听错误状态
mediaPlayer.setOnErrorListener((mp, what, extra) -> {
LoggerUtil.e("MediaPlayer", "Error: " + what + ", " + extra);
// 出错后释放资源
mp.release();
mediaPlayer = null;
return true;
});
} catch (IOException e) {
e.printStackTrace();
// 处理文件读取错误(如路径无效、权限不足)
}
}
public static void stopPlay(){
if(mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
}

235
app/src/main/java/qianmu/container/util/Base64Util.java

@ -0,0 +1,235 @@
package qianmu.container.util;
/**
* Created by Android Studio.
* User: linzhibin
* Date: 2025/11/26
* Time: 19:22
*/
class Base64Util {
static private final int BASELENGTH = 128;
static private final int LOOKUPLENGTH = 64;
static private final int TWENTYFOURBITGROUP = 24;
static private final int EIGHTBIT = 8;
static private final int SIXTEENBIT = 16;
static private final int FOURBYTE = 4;
static private final int SIGN = -128;
static private final char PAD = '=';
static private final boolean fDebug = false;
static final private byte[] base64Alphabet = new byte[BASELENGTH];
static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
static {
for (int i = 0; i < BASELENGTH; ++i) {
base64Alphabet[i] = -1;
}
for (int i = 'Z'; i >= 'A'; i--) {
base64Alphabet[i] = (byte) (i - 'A');
}
for (int i = 'z'; i >= 'a'; i--) {
base64Alphabet[i] = (byte) (i - 'a' + 26);
}
for (int i = '9'; i >= '0'; i--) {
base64Alphabet[i] = (byte) (i - '0' + 52);
}
base64Alphabet['+'] = 62;
base64Alphabet['/'] = 63;
for (int i = 0; i <= 25; i++) {
lookUpBase64Alphabet[i] = (char) ('A' + i);
}
for (int i = 26, j = 0; i <= 51; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('a' + j);
}
for (int i = 52, j = 0; i <= 61; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('0' + j);
}
lookUpBase64Alphabet[62] = '+';
lookUpBase64Alphabet[63] = '/';
}
private static boolean isWhiteSpace(char octect) {
return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
}
private static boolean isPad(char octect) {
return (octect == PAD);
}
private static boolean isData(char octect) {
return (octect < BASELENGTH && base64Alphabet[octect] != -1);
}
/**
* 将十六进制八位字节编码为Base64
*
* @param binaryData 包含二进制数据的数组
* @return 编码Base64字符串
*/
public static String encode(byte[] binaryData) {
if (binaryData == null) {
return null;
}
int lengthDataBits = binaryData.length * EIGHTBIT;
if (lengthDataBits == 0) {
return "";
}
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
char[] encodedData = new char[numberQuartet * 4];
byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
int encodedIndex = 0;
int dataIndex = 0;
if (fDebug) {
System.out.println("number of triplets = " + numberTriplets);
}
for (int i = 0; i < numberTriplets; i++) {
b1 = binaryData[dataIndex++];
b2 = binaryData[dataIndex++];
b3 = binaryData[dataIndex++];
if (fDebug) {
System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
}
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
if (fDebug) {
System.out.println("val2 = " + val2);
System.out.println("k4 = " + (k << 4));
System.out.println("vak = " + (val2 | (k << 4)));
}
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
}
if (fewerThan24bits == EIGHTBIT) {
b1 = binaryData[dataIndex];
k = (byte) (b1 & 0x03);
if (fDebug) {
System.out.println("b1=" + b1);
System.out.println("b1<<2 = " + (b1 >> 2));
}
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
encodedData[encodedIndex++] = PAD;
encodedData[encodedIndex++] = PAD;
} else if (fewerThan24bits == SIXTEENBIT) {
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
encodedData[encodedIndex++] = PAD;
}
return new String(encodedData);
}
/**
* 将Base64数据解码为八位字节
*
* @param encoded 包含Base64数据的字符串
* @return 包含解码数据的数组.
*/
public static byte[] decode(String encoded) {
if (encoded == null) {
return null;
}
char[] base64Data = encoded.toCharArray();
//删除空白
int len = removeWhiteSpace(base64Data);
//应该可以被四整除
if (len % FOURBYTE != 0) {
return null;
}
int numberQuadruple = (len / FOURBYTE);
if (numberQuadruple == 0) {
return new byte[0];
}
byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
int i = 0;
int encodedIndex = 0;
int dataIndex = 0;
byte[] decodedData = new byte[(numberQuadruple) * 3];
for (; i < numberQuadruple - 1; i++) {
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
|| !isData((d3 = base64Data[dataIndex++]))
|| !isData((d4 = base64Data[dataIndex++]))) {
return null;
}//没有数据直接返回null
b1 = base64Alphabet[d1];
b2 = base64Alphabet[d2];
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
}
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
return null;////没有数据直接返回null
}
b1 = base64Alphabet[d1];
b2 = base64Alphabet[d2];
d3 = base64Data[dataIndex++];
d4 = base64Data[dataIndex++];
if (!isData((d3)) || !isData((d4))) {
//检查是否为填充字符
if (isPad(d3) && isPad(d4)) {
if ((b2 & 0xf) != 0) {//最后四位应为0
return null;
}
byte[] tmp = new byte[i * 3 + 1];
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
return tmp;
} else if (!isPad(d3) && isPad(d4)) {
b3 = base64Alphabet[d3];
if ((b3 & 0x3) != 0){//最后2位应为零
return null;
}
byte[] tmp = new byte[i * 3 + 2];
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
return tmp;
} else {
return null;
}
} else { //No PAD e.g 3cQl
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
}
return decodedData;
}
/**
* 从包含编码Base64数据的MIME中删除空白
*
* @param data base64数据的字节数组带空白
* @return 新的长度
*/
private static int removeWhiteSpace(char[] data) {
if (data == null) {
return 0;
}
int newSize = 0;
int len = data.length;
for (int i = 0; i < len; i++) {
if (!isWhiteSpace(data[i])) {
data[newSize++] = data[i];
}
}
return newSize;
}
}

86
app/src/main/java/qianmu/container/util/DeviceUtil.java

@ -19,6 +19,7 @@ import java.io.File;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.List;
@ -45,7 +46,11 @@ public class DeviceUtil {
try {
if(Constant.androidBoardType.equals("nova")){
//诺瓦
return getEthIpAddress();
String ip = getEthIpAddress();
if(StringUtil.isEmpty(ip)){
ip = getLocalIPByWIFI();
}
return ip;
}else {
String allIP = "";
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
@ -92,7 +97,7 @@ public class DeviceUtil {
//获取有线网络ip
public static String getEthIpAddress() {
String infaceName = "eth0";
String ip = "0.0.0.0";
String ip = "";
try {
Enumeration<NetworkInterface> netInterface = NetworkInterface.getNetworkInterfaces();
while (netInterface.hasMoreElements()) {
@ -100,12 +105,10 @@ public class DeviceUtil {
if (!inface.isUp()) {
continue;
}
// eth0 有线网络判断
if (!infaceName.equals(inface.getDisplayName())) {
continue;
}
Enumeration<InetAddress> netAddressList = inface.getInetAddresses();
while (netAddressList.hasMoreElements()) {
InetAddress inetAddress = netAddressList.nextElement();
@ -123,7 +126,6 @@ public class DeviceUtil {
//获取有线网络mac
public static String getLanMac(){
ConnectivityManager cm = (ConnectivityManager) MyApplication.getInstance().getApplicationContext().getSystemService(Service.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
String extraInfo = activeNetworkInfo.getExtraInfo();
@ -136,27 +138,36 @@ public class DeviceUtil {
* @return
*/
public static String getLocalIPByWIFI() {
String ip="";
try {
//获取wifi服务
WifiManager wifiManager = (WifiManager) MyApplication.getInstance().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
//判断wifi是否开启
if (!wifiManager.isWifiEnabled()) wifiManager.setWifiEnabled(true);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
return intToIp(ipAddress);
} catch (Throwable t) {
LoggerUtil.e("getLocalIPByWIFI", StringUtil.getThrowableStr(t));
return "";
Socket socket = new Socket("www.baidu.com",80);
ip = socket.getLocalAddress().toString();
LoggerUtil.e("GETIP: ", ip);
} catch (Exception e) {
Log.e(TAG, "网络接口遍历获取IP失败", e);
}
if("".equals(ip)){
try {
//获取wifi服务
WifiManager wifiManager = (WifiManager) MyApplication.getInstance().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
//判断wifi是否开启
if (!wifiManager.isWifiEnabled()) wifiManager.setWifiEnabled(true);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
ip = intToIp(ipAddress);
} catch (Throwable t) {
LoggerUtil.e("getLocalIPByWIFI", StringUtil.getThrowableStr(t));
return "";
}
}
return ip;
}
private static String intToIp(int i) {
String first = String.valueOf((i & 0xFF));
String second = String.valueOf(((i >> 8) & 0xFF));
String third = String.valueOf(((i >> 16) & 0xFF));
String fourth = String.valueOf((i >> 24 & 0xFF));
return StringUtil.strSplice(first, ".", second, ".", third, ".", fourth);
}
@ -195,23 +206,38 @@ public class DeviceUtil {
* @return
*/
public static String getLocalMacAddressFromIp() {
String strMacAddr = null;
String macAddress="";
WifiManager wifiManager = (WifiManager) MyApplication.getInstance().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
macAddress = wifiInfo.getBSSID();
if(StringUtil.isEmpty(macAddress)){
macAddress = getMacFromNetworkInterface();
}
return macAddress;
}
/**
* 通过网络接口获取MAC地址备选方案
*/
private static String getMacFromNetworkInterface() {
try {
//获得IpD地址
InetAddress ip = getLocalInetAddress();
byte[] b = NetworkInterface.getByInetAddress(ip).getHardwareAddress();
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < b.length; i++) {
if (i != 0) {
buffer.append(':');
}
String str = Integer.toHexString(b[i] & 0xFF);
buffer.append(str.length() == 1 ? 0 + str : str);
java.net.NetworkInterface networkInterface = java.net.NetworkInterface.getByName("wlan0");
if (networkInterface == null) return "";
byte[] macBytes = networkInterface.getHardwareAddress();
if (macBytes == null) return "";
StringBuilder mac = new StringBuilder();
for (byte b : macBytes) {
mac.append(String.format("%02X:", b));
}
strMacAddr = buffer.toString().toUpperCase();
if (mac.length() > 0) {
mac.deleteCharAt(mac.length() - 1);
}
return mac.toString();
} catch (Exception e) {
Log.e(TAG, "通过网络接口获取MAC失败", e);
return "";
}
return strMacAddr;
}
/**
* 获取移动设备本地IP

59
app/src/main/java/qianmu/container/util/FileUtil.java

@ -92,12 +92,6 @@ public class FileUtil {
@Override
public void onError(Response<File> response) {
super.onError(response);
try{
downloadSuccess(response, tempFilePath);
}catch (Exception e){
if (finishListener != null) finishListener.onFinish();
}
if (finishListener != null) finishListener.onFinish();
}
@Override
@ -149,18 +143,13 @@ public class FileUtil {
public void onError(Response<File> response) {
super.onError(response);
LoggerUtil.e("素材下载失败", "文件:"+tempFilePath+","+response.message());
try{
downloadSuccess(response, tempFilePath);
}catch (Exception e){
if (finishListener != null) finishListener.onFinish();
}
if (finishListener != null) finishListener.onFinish();
}
@Override
public void onFinish() {
super.onFinish();
downloadFiles.remove(targetPath);
}
});
} catch (Throwable t) {
@ -179,24 +168,38 @@ public class FileUtil {
try {
String fileTotalLength = response.headers().get("Content-Range");
//获取请求数据的总大小
fileTotalLength = fileTotalLength.substring(fileTotalLength.lastIndexOf("/") + 1);
File tempFile = new File(localPath);
//读取本地保存文件大小
String tempFileLength = String.valueOf(tempFile.length());
//二者大小一致时 修改文件后缀名
if (tempFile.length()!=0 &&fileTotalLength.equals(tempFileLength)) {
String targetPath = localPath.substring(0, localPath.lastIndexOf("."));
if(targetPath.contains("?")){
String[] split = targetPath.split("[?]");
targetPath=split[0];
if( StringUtil.isEmpty(fileTotalLength)){
if(tempFile.length() > 10){
String targetPath = localPath.substring(0, localPath.lastIndexOf("."));
if(targetPath.contains("?")){
String[] split = targetPath.split("[?]");
targetPath=split[0];
}
File targetFile = new File(targetPath);
tempFile.renameTo(targetFile);
}else{
tempFile.delete();
}
}else{
//获取请求数据的总大小
fileTotalLength = fileTotalLength.substring(fileTotalLength.lastIndexOf("/") + 1);
//读取本地保存文件大小
String tempFileLength = String.valueOf(tempFile.length());
//二者大小一致时 修改文件后缀名
if (tempFile.length()!=0 &&fileTotalLength.equals(tempFileLength)) {
String targetPath = localPath.substring(0, localPath.lastIndexOf("."));
if(targetPath.contains("?")){
String[] split = targetPath.split("[?]");
targetPath=split[0];
}
File targetFile = new File(targetPath);
tempFile.renameTo(targetFile);
} else{
Log.e("下载失败", localPath);
//本地文件大于待下载文件时 表示断点下载异常 删除已下载文件
tempFile.delete();
}
File targetFile = new File(targetPath);
tempFile.renameTo(targetFile);
} else{
Log.e("下载失败", localPath);
//本地文件大于待下载文件时 表示断点下载异常 删除已下载文件
tempFile.delete();
}
} catch (Throwable t) {
LoggerUtil.e("downloadSuccess", StringUtil.getThrowableStr(t));

103
app/src/main/java/qianmu/container/util/SignUtil.java

@ -0,0 +1,103 @@
package qianmu.container.util;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Locale;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import cn.hutool.core.util.ObjectUtil;
import qianmu.container.data.DeviceData;
import qianmu.container.data.FloorData;
/**
* Created by Android Studio.
* User: linzhibin
* Date: 2025/11/26
* Time: 19:16
*/
public class SignUtil {
private static final String SignAlgorithm = "HmacSHA256";
public static Boolean checkSign(String activationCode, String projectCode, Long timeStrap, String sk) {
if (ObjectUtil.isEmpty(sk)) {
return false;
}
long thisTime = System.currentTimeMillis();
// 大于/小于5min则过期
long diff = thisTime - timeStrap;
if (diff < -1000 * 60 * 5 || diff > 1000 * 60 * 5) {
return false;
}
String anObject = buildSk(activationCode, projectCode, timeStrap);
boolean equals = sk.equals(anObject);
return equals;
}
/**
* activationCode+timeStrap作为ak,projectCode为盐值
*/
public static String buildSk(String activationCode, String projectCode, Long timeStrap) {
String ak = activationCode + timeStrap;
return sign(projectCode, ak);
}
/**
* 生成签名 哈希后转16进制再sha256加密,最后转base64
* @param secret 秘钥
* @param content 待签名内容
*/
public static String sign(String secret, String content) {
try {
Mac mac = Mac.getInstance(SignAlgorithm);
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), SignAlgorithm));
String data = toHex(hash(content));
byte[] signByte = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64Util.encode(toHex(signByte).getBytes());
} catch (NoSuchAlgorithmException | InvalidKeyException ex) {
return null;
}
}
public static byte[] hash(String text) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(text.getBytes(StandardCharsets.UTF_8));
return md.digest();
} catch (NoSuchAlgorithmException ex) {
return null;
}
}
public static String toHex(byte[] data) {
StringBuilder sb = new StringBuilder(data.length * 2);
for (byte b : data) {
String hex = Integer.toHexString(b);
if (hex.length() == 1) {
sb.append("0");
} else if (hex.length() == 8) {
hex = hex.substring(6);
}
sb.append(hex);
}
return sb.toString().toLowerCase(Locale.getDefault());
}
public static void main(String[] args) {
long timeStrap = System.currentTimeMillis();
String regKey = DeviceData.getDeviceInfo(DeviceData.HINT_REG_KEY);
String mallCode = FloorData.getMallCode();
System.out.println(SignUtil.buildSk(regKey, mallCode, timeStrap));
System.out.println(timeStrap);
}
}

16
app/src/main/java/qianmu/container/util/SignWayUtil.java

@ -131,7 +131,6 @@ public class SignWayUtil {
LoggerUtil.e("SignwayUtil", "app安装结果:"+msg);
}
});
}else if(Constant.androidBoardType.equals("sx")){
Intent intent = new Intent("android.intent.action.apkinstall");
intent.putExtra("path",path);
@ -140,6 +139,7 @@ public class SignWayUtil {
}else if(Constant.androidBoardType.equals("zc")){
zcapi zcApi=new zcapi();
zcApi.getContext(MyApplication.getInstance());
LoggerUtil.e("appInstall: ",path);
zcApi.InstallApk(path,true);
}else if(Constant.androidBoardType.equals("nova")){
MessageEvent messageEvent = new MessageEvent(Constant.NOVA_UPDATE_APP);
@ -147,8 +147,7 @@ public class SignWayUtil {
EventBus.getDefault().post(messageEvent);
}else if(Constant.androidBoardType.equals("huidu")){
HuiduTech helper = new HuiduTech(MyApplication.getInstance());
// helper.install(path);
helper.installAndStart(path,"qianmu.container","qianmu.container.activity.H5.UpdateFileActivity");
helper.install(path);
}
} catch (Throwable t) {
LoggerUtil.e("silentInstallApk", StringUtil.getThrowableStr(t));
@ -323,6 +322,8 @@ public class SignWayUtil {
if(Constant.androidBoardType.equals("xwst")){
SignwayManager signwayManager = SignwayManager.getInstance(MyApplication.getInstance());
signwayManager.takeScreenshot(path, 0);
}else if(Constant.androidBoardType.equals("smt")){
MyApplication.getInstance().getSmdt().disp_getScreenShot(path);
}else if(Constant.androidBoardType.equals("ys")){
Log.e("TAG","开始截屏");
MyManager manager = MyManager.getInstance(MyApplication.getInstance());
@ -371,6 +372,8 @@ public class SignWayUtil {
}else if(Constant.androidBoardType.equals("smt")){
MyApplication.getInstance().getSmdt().disp_setStatusBar(type);
MyApplication.getInstance().getSmdt().disp_setNavigationBar(type);
MyApplication.getInstance().getSmdt().disp_setStatusBarDrag(type);
MyApplication.getInstance().getSmdt().disp_setGestureBar(type);
}else if(Constant.androidBoardType.equals("sx")){
Intent intent = new Intent("rk.android.remove_navigationbar");
MyApplication.getInstance().sendBroadcast(intent);
@ -430,8 +433,11 @@ public class SignWayUtil {
zcApi.getContext(MyApplication.getInstance());
return zcApi.getEthMacAddress("eth0");
}if(Constant.androidBoardType.equals("nova")){
return DeviceUtil.getLanMac();
// return DeviceUtil.getMacFromHardware();
String mac = DeviceUtil.getLanMac();
if(StringUtil.isEmpty(mac)){
mac = DeviceUtil.getMacFromHardware();
}
return mac;
}
else if(Constant.androidBoardType.equals("huidu")){

179
app/src/main/java/qianmu/container/util/TTSUtil.java

@ -0,0 +1,179 @@
package qianmu.container.util;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import androidx.annotation.NonNull;
import com.iflytek.sparkchain.core.tts.OnlineTTS;
import com.iflytek.sparkchain.core.tts.TTS;
import com.iflytek.sparkchain.core.tts.TTSCallbacks;
import org.greenrobot.eventbus.EventBus;
import qianmu.container.app.Constant;
import qianmu.container.entity.MessageEvent;
public class TTSUtil {
private static String TAG = "TTS: ";
// 语音合成对象
private OnlineTTS mOnlineTTS;
private int sampleRate = 16000;
TTSCallbacks mTTSCallback = new TTSCallbacks() {
@Override
public void onResult(TTS.TTSResult result, Object o) {
//解析获取的交互结果,示例展示所有结果获取,开发者可根据自身需要,选择获取。
byte[] audio = result.getData();//音频数据
int status = result.getStatus();//数据状态
Bundle bundle = new Bundle();
bundle.putByteArray("audio", audio);
Message msg = mAudioPlayHandler.obtainMessage();
msg.what = AUDIOPLAYER_WRITE;
msg.obj = bundle;
mAudioPlayHandler.sendMessage(msg);
if(status == 2){
//音频合成回调结束状态,注意,此状态不是播报完成状态
mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_END);
}
}
@Override
public void onError(TTS.TTSError ttsError, Object o) {
int errCode = ttsError.getCode();//错误码
String errMsg = ttsError.getErrMsg();//错误信息
LoggerUtil.d(TAG, "onError:errCode:" + errCode+ ",errMsg:" + errMsg);
//如果此时已经播报,则停止播报
EventBus.getDefault().post(new MessageEvent(Constant.VOID_STOP));
stopTTs();
}
};
public void initTts(){
mAudioPlayThread.start();
// 初始化合成对象 发音人
mOnlineTTS = new OnlineTTS("xiaoyan"); //xiaoyan
}
//开始听写
public void startTTs(String texts){
if (null == mOnlineTTS) {
LoggerUtil.d(TAG, "未初始化");
initTts();
}
if(audioTrack == null){
mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_INIT);
}else{
mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_START);
}
setParam();
// 合成并播放
int ret = mOnlineTTS.aRun(texts);
if(ret!=0){
LoggerUtil.d(TAG, "语音合成失败" );
}
}
//停止听写
public void stopTTs(){
LoggerUtil.d(TAG, "手动暂停播放");
if (null == mOnlineTTS) {
LoggerUtil.d(TAG, "未初始化");
return;
}
mAudioPlayHandler.removeCallbacksAndMessages(null);
mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_END);
mOnlineTTS.stop();
}
/**
* 参数设置
*
* @return
*/
private void setParam() {
mOnlineTTS.aue("raw");
mOnlineTTS.auf("audio/L16;rate="+sampleRate); // 8K 或 16K
mOnlineTTS.speed(60);//语速:0对应默认语速的1/2,100对应默认语速的2倍。最⼩值:0, 最⼤值:100
mOnlineTTS.pitch(50);//语调:0对应默认语速的1/2,100对应默认语速的2倍。最⼩值:0, 最⼤值:100
mOnlineTTS.volume(80);//音量:0是静音,1对应默认音量1/2,100对应默认音量的2倍。最⼩值:0, 最⼤值:100
mOnlineTTS.bgs(0); //合成音频的背景音 0:无背景音(默认值) 1:有背景音
mOnlineTTS.tte("UTF8");
mOnlineTTS.registerCallbacks(mTTSCallback);
}
/**
* 播放器用于播报合成的音频
* 注意当前Demo中的播放器仅实现了播放PCM格式的音频如果客户合成的是其他格式的音频需自行实现播放功能
*/
private static final int AUDIOPLAYER_INIT = 0x0000;
private static final int AUDIOPLAYER_START = 0x0001;
private static final int AUDIOPLAYER_WRITE = 0x0002;
private static final int AUDIOPLAYER_END = 0x0003;
private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_OUT_MONO; // 单声道输出
private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; // PCM 16位编码
private AudioTrack audioTrack;
private Handler mAudioPlayHandler;
private boolean isPlaying = false;
int count = 0;
private Thread mAudioPlayThread = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
mAudioPlayHandler = new Handler(Looper.myLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch(msg.what){
case AUDIOPLAYER_INIT:
Log.d(TAG,"audioInit");
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, CHANNEL_CONFIG, AUDIO_FORMAT);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, CHANNEL_CONFIG, AUDIO_FORMAT, minBufferSize, AudioTrack.MODE_STREAM);
mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_START);
break;
case AUDIOPLAYER_START:
Log.d(TAG,"audioStart");
if(audioTrack!=null) {
isPlaying = true;
audioTrack.play();
}
break;
case AUDIOPLAYER_WRITE:
count ++;
if(count%5 == 0){
Log.d(TAG,"audioWrite");
count = 0;
}
Bundle bundle = (Bundle) msg.obj;
byte[] audioData = bundle.getByteArray("audio");
if(audioTrack!=null&&audioData.length>0){
audioTrack.write(audioData,0,audioData.length);
}
break;
case AUDIOPLAYER_END:
Log.d(TAG,"audioEnd");
EventBus.getDefault().post(new MessageEvent(Constant.VOID_STOP));
if(audioTrack!=null) {
audioTrack.stop();
audioTrack.release();
audioTrack = null;
isPlaying = false;
}
break;
}
}
};
Looper.loop();
}
});
}

37
app/src/main/res/layout/activity_test.xml

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.TestActivity"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="@dimen/aspect_btn_height"
android:layout_weight="1"
android:text="开始语音识别" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="停止语音识别" />
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="播放语音合成" />
<Button
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="停止语音合成" />
</LinearLayout>

45
app/src/main/res/layout/activity_webview.xml

@ -6,11 +6,56 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout android:layout_height="match_parent"
android:layout_width="match_parent" >
<VideoView
android:id="@+id/bgVideo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
/>
<VideoView
android:id="@+id/helloVideo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<VideoView
android:id="@+id/speekVideo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<VideoView
android:id="@+id/backVideo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<VideoView
android:id="@+id/toVideo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<VideoView
android:id="@+id/bgVideo1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<VideoView
android:id="@+id/helloVideo1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<VideoView
android:id="@+id/speekVideo1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
</RelativeLayout>
<WebView
android:id="@+id/web"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
/>
<ImageView

BIN
app/src/main/res/raw/bg.mp4

Binary file not shown.

BIN
app/src/main/res/raw/bg_old.mp4

Binary file not shown.

BIN
app/src/main/res/raw/hello.mp4

Binary file not shown.

BIN
app/src/main/res/raw/hello_old.mp4

Binary file not shown.

BIN
app/src/main/res/raw/musice.mp3

Binary file not shown.

BIN
app/src/main/res/raw/speek.mp4

Binary file not shown.

BIN
app/src/main/res/raw/speek_old.mp4

Binary file not shown.

3
app/src/main/res/values/strings.xml

@ -1,4 +1,7 @@
<resources>
<string name="appid">deb3f3ab</string>
<string name="apiSecret">MGRjYzQwZjExMTI4YjA3MzZmZTdjZjVm</string>
<string name="apikey">daf84ac85c24e300a517c7ef96744b25</string>
<string name="app_name">Android容器</string>
<string name="register_state">设备注册状态:</string>
<string name="hint_mall_code">商场编号:</string>

3
app/src/main/res/values/styles.xml

@ -6,6 +6,9 @@
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
</resources>

10
playerview/build.gradle

@ -12,7 +12,7 @@ android {
versionCode 4
versionName "1.0.3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@ -26,13 +26,13 @@ android {
dependencies {
api fileTree(dir: 'libs', include: ['*.jar'])
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'com.android.support:appcompat-v7:24.2.1'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
// ijkplayer
api 'tv.danmaku.ijk.media:ijkplayer-java:0.7.8.1'
api 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.7.8.1'

6
playerview/src/androidTest/java/com/dl7/player/ExampleInstrumentedTest.java

@ -1,8 +1,8 @@
package com.dl7.player;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -19,7 +19,7 @@ public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.dl7.playerview.test", appContext.getPackageName());
}

Loading…
Cancel
Save