只带wifi的充电桩app

master
hzh 2 months ago
commit ed3c4a4700
  1. 88
      .gitignore
  2. 3
      .idea/.gitignore
  3. 1
      .idea/.name
  4. 46
      .idea/appInsightsSettings.xml
  5. 16
      .idea/checkstyle-idea.xml
  6. 6
      .idea/compiler.xml
  7. 13
      .idea/deploymentTargetDropDown.xml
  8. 36
      .idea/deploymentTargetSelector.xml
  9. 6
      .idea/inspectionProfiles/Project_Default.xml
  10. 6
      .idea/kotlinc.xml
  11. 10
      .idea/migrations.xml
  12. 15
      .idea/misc.xml
  13. 6
      .idea/studiobot.xml
  14. 20
      README.md
  15. 1
      alarm/.gitignore
  16. 27
      alarm/build.gradle
  17. 21
      alarm/proguard-rules.pro
  18. 26
      alarm/src/androidTest/java/com/snc/alarm/ExampleInstrumentedTest.java
  19. 14
      alarm/src/main/AndroidManifest.xml
  20. 26
      alarm/src/main/alone/AndroidManifest.xml
  21. 20
      alarm/src/main/java/com/snc/alarm/AlarmModuleInit.java
  22. 22
      alarm/src/main/java/com/snc/alarm/adapter/AlarmListAdapter.java
  23. 212
      alarm/src/main/java/com/snc/alarm/ui/AlarmListActivity.java
  24. 45
      alarm/src/main/res/layout/activity_alarm_list.xml
  25. 35
      alarm/src/main/res/layout/item_alarmlist.xml
  26. 17
      alarm/src/test/java/com/snc/alarm/ExampleUnitTest.java
  27. 1
      app/.gitignore
  28. BIN
      app/EViveCharger.jks
  29. 121
      app/build.gradle
  30. 718
      app/proguard-rules.pro
  31. 312252
      app/proguardMapping.txt
  32. 26
      app/src/androidTest/java/com/snc/evivecharger/ExampleInstrumentedTest.java
  33. 122
      app/src/main/AndroidManifest.xml
  34. 13
      app/src/main/java/com/snc/evivecharger/AppApplication.java
  35. 17
      app/src/test/java/com/snc/evivecharger/ExampleUnitTest.java
  36. 1
      ble/.gitignore
  37. 32
      ble/build.gradle
  38. 21
      ble/proguard-rules.pro
  39. 26
      ble/src/androidTest/java/com/snc/ble/ExampleInstrumentedTest.java
  40. 21
      ble/src/main/AndroidManifest.xml
  41. 121
      ble/src/main/alone/AndroidManifest.xml
  42. 20
      ble/src/main/java/com/snc/ble/BleModuleInit.java
  43. 25
      ble/src/main/java/com/snc/ble/adapter/BleDeviceAdapter.java
  44. 135
      ble/src/main/java/com/snc/ble/bean/BleBean.java
  45. 41
      ble/src/main/java/com/snc/ble/bean/SendBle.java
  46. 4
      ble/src/main/java/com/snc/ble/constant/BleConstant.java
  47. 484
      ble/src/main/java/com/snc/ble/ui/BleActivity.java
  48. 106
      ble/src/main/java/com/snc/ble/ui/BlechargActivity.java
  49. 45
      ble/src/main/res/layout/activity_ble.xml
  50. 121
      ble/src/main/res/layout/activity_blecharg.xml
  51. 69
      ble/src/main/res/layout/item_ble_device.xml
  52. 17
      ble/src/test/java/com/snc/ble/ExampleUnitTest.java
  53. 29
      build.gradle
  54. 26
      gradle.properties
  55. BIN
      gradle/wrapper/gradle-wrapper.jar
  56. 6
      gradle/wrapper/gradle-wrapper.properties
  57. 172
      gradlew
  58. 84
      gradlew.bat
  59. 1
      history/.gitignore
  60. 27
      history/build.gradle
  61. 21
      history/proguard-rules.pro
  62. 26
      history/src/androidTest/java/com/snc/history/ExampleInstrumentedTest.java
  63. 6
      history/src/main/AndroidManifest.xml
  64. 14
      history/src/main/alone/AndroidManifest.xml
  65. 20
      history/src/main/java/com/snc/history/HistoryModuleInit.java
  66. 28
      history/src/main/java/com/snc/history/adapter/HistoryAdapter.java
  67. 157
      history/src/main/java/com/snc/history/ui/HistoryFragment.java
  68. 56
      history/src/main/res/layout/fragment_history.xml
  69. 153
      history/src/main/res/layout/item_history.xml
  70. 17
      history/src/test/java/com/snc/history/ExampleUnitTest.java
  71. 1
      home/.gitignore
  72. 27
      home/build.gradle
  73. 21
      home/proguard-rules.pro
  74. 26
      home/src/androidTest/java/com/snc/home/ExampleInstrumentedTest.java
  75. 6
      home/src/main/AndroidManifest.xml
  76. 14
      home/src/main/alone/AndroidManifest.xml
  77. 20
      home/src/main/java/com/snc/home/HomeModuleInit.java
  78. 50
      home/src/main/java/com/snc/home/adapter/DeviceListAdapter.java
  79. 549
      home/src/main/java/com/snc/home/ui/HomeFragment.java
  80. 69
      home/src/main/res/layout/fragment_home.xml
  81. 20
      home/src/main/res/layout/home_footer.xml
  82. 134
      home/src/main/res/layout/item_home_device_list.xml
  83. 17
      home/src/test/java/com/snc/home/ExampleUnitTest.java
  84. 1
      lib_base/.gitignore
  85. 114
      lib_base/build.gradle
  86. 0
      lib_base/consumer-rules.pro
  87. 235
      lib_base/proguard-rules.pro
  88. 11
      lib_base/src/main/AndroidManifest.xml
  89. 22
      lib_base/src/main/assets/ca.crt
  90. 1
      lib_base/src/main/assets/charging.json
  91. 1
      lib_base/src/main/assets/loading.json
  92. 80
      lib_base/src/main/java/com/snc/base/adapter/CustomLoadMoreView.java
  93. 32
      lib_base/src/main/java/com/snc/base/adapter/animator/CustomAnimation1.java
  94. 40
      lib_base/src/main/java/com/snc/base/adapter/animator/CustomAnimation2.java
  95. 27
      lib_base/src/main/java/com/snc/base/adapter/animator/CustomAnimation3.java
  96. 207
      lib_base/src/main/java/com/snc/base/base/AppManager.java
  97. 473
      lib_base/src/main/java/com/snc/base/base/BaseActivity.java
  98. 81
      lib_base/src/main/java/com/snc/base/base/BaseApplication.java
  99. 106
      lib_base/src/main/java/com/snc/base/base/BaseFragment.java
  100. 163
      lib_base/src/main/java/com/snc/base/base/BaseModuleInit.java
  101. Some files were not shown because too many files have changed in this diff Show More

88
.gitignore vendored

@ -0,0 +1,88 @@
# Built application files
*.apk
*.aar
*.ap_
*.aab
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Uncomment the following line in case you need and you don't have the release build type files in your app
# release/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
# Android Studio 3 in .gitignore file.
.idea/caches
.idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
.idea/navEditor.xml
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
#*.jks
#*.keystore
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
.cxx/
# Google Services (e.g. APIs or Firebase)
# google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md
# Version control
vcs.xml
# lint
lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/
# Android Profiling
*.hprof

3
.idea/.gitignore vendored

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

@ -0,0 +1 @@
wifi EVive-Charger

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AppInsightsSettings">
<option name="selectedTabId" value="Android Vitals" />
<option name="tabSettings">
<map>
<entry key="Android Vitals">
<value>
<InsightsFilterSettings>
<option name="connection">
<ConnectionSetting>
<option name="appId" value="com.snc.charging.h" />
</ConnectionSetting>
</option>
<option name="failureTypes">
<list>
<option value="FATAL" />
</list>
</option>
<option name="signal" value="SIGNAL_UNSPECIFIED" />
<option name="timeIntervalDays" value="SEVEN_DAYS" />
<option name="visibilityType" value="ALL" />
</InsightsFilterSettings>
</value>
</entry>
<entry key="Firebase Crashlytics">
<value>
<InsightsFilterSettings>
<option name="connection">
<ConnectionSetting>
<option name="appId" value="PLACEHOLDER" />
<option name="mobileSdkAppId" value="" />
<option name="projectId" value="" />
<option name="projectNumber" value="" />
</ConnectionSetting>
</option>
<option name="signal" value="SIGNAL_UNSPECIFIED" />
<option name="timeIntervalDays" value="THIRTY_DAYS" />
<option name="visibilityType" value="ALL" />
</InsightsFilterSettings>
</value>
</entry>
</map>
</option>
</component>
</project>

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA" serialisationVersion="2">
<checkstyleVersion>10.12.5</checkstyleVersion>
<scanScope>JavaOnly</scanScope>
<copyLibs>true</copyLibs>
<option name="thirdPartyClasspath" />
<option name="activeLocationIds" />
<option name="locations">
<list>
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
</list>
</option>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
</entry>
<entry key="web">
<State />
</entry>
</value>
</component>
</project>

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-05-20T01:37:54.921297400Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=2f5108f4" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
<SelectionState runConfigName="home">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="history">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="settings">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="schedules">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="alarm">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="ble">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AndroidLintUnsafeImplicitIntentLaunch" enabled="false" level="ERROR" enabled_by_default="false" />
</profile>
</component>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.0" />
</component>
</project>

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

@ -0,0 +1,15 @@
<project version="4">
<component name="ASMSmaliIdeaPluginConfiguration">
<asm skipDebug="true" skipFrames="true" skipCode="false" expandFrames="false" />
<groovy codeStyle="LEGACY" />
</component>
<component name="FileUpload">
<url />
<module />
<path />
<params />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="StudioBotProjectSettings">
<option name="shareContext" value="OptedIn" />
</component>
</project>

@ -0,0 +1,20 @@
#### 说明
组件化项目
app 组成项目EVive-Charger应用的入口:将业务组件打包成一个APP,做一些配置工作。(打包环境、签名、混淆等)
业务模块 根据业务分类
mian 主模块
login 登录注册模块
wifi wifi模块
web 浏览器模块
schedules 定时充电模块
home 首页模块
history 历史模块
settings 设置模块
alarm 告警模块
ble 纯蓝牙模式
基础组件
lib_base
统一依赖配置和资源文件:引入第三方框架(Retrofit、Glide)、存放公用资源文件(strings、drawable、自定义View、工具类Utils)、实现路由(ARouter)。修改频率极低。

1
alarm/.gitignore vendored

@ -0,0 +1 @@
/build

@ -0,0 +1,27 @@
apply from: "../module.build.gradle"
android {
namespace 'com.snc.alarm'
defaultConfig {
//使
if (isModule.toBoolean()) {
namespace 'com.snc.alarm'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
kapt 'com.alibaba:arouter-compiler:1.5.2'
//宿
api project(':lib_base')
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,26 @@
package com.snc.alarm;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.snc.alarm", appContext.getPackageName());
}
}

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".ui.AlarmListActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|adjustNothing|stateHidden" />
</application>
</manifest>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name="com.snc.base.debug.DebugApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".ui.AlarmListActivity"
android:configChanges="orientation|screenSize"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|adjustNothing|stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

@ -0,0 +1,20 @@
package com.snc.alarm;
import android.app.Application;
import com.snc.base.base.IModuleInit;
import com.snc.base.utils.LogUtils;
public class AlarmModuleInit implements IModuleInit {
@Override
public boolean onInitAhead(Application application) {
LogUtils.e("告警模块 -- onInitAhead");
return false;
}
@Override
public boolean onInitLow(Application application) {
LogUtils.e("告警模块 -- onInitLow");
return false;
}
}

@ -0,0 +1,22 @@
package com.snc.alarm.adapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.module.LoadMoreModule;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.snc.base.bean.AlarmBean;
import com.snc.alarm.R;
import java.util.List;
public class AlarmListAdapter extends BaseQuickAdapter<AlarmBean, BaseViewHolder> implements LoadMoreModule {
public AlarmListAdapter(@Nullable List<AlarmBean> data) {
super(R.layout.item_alarmlist, data);
}
@Override
protected void convert(@NonNull BaseViewHolder baseViewHolder, AlarmBean alarmBean) {
baseViewHolder.setText(R.id.info, alarmBean.getInfo());
}
}

@ -0,0 +1,212 @@
package com.snc.alarm.ui;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.graphics.Color;
import android.view.View;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.alibaba.android.arouter.facade.annotation.Autowired;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnLoadMoreListener;
import com.hjq.http.EasyHttp;
import com.hjq.http.listener.OnHttpListener;
import com.snc.alarm.R;
import com.snc.alarm.adapter.AlarmListAdapter;
import com.snc.alarm.databinding.ActivityAlarmListBinding;
import com.snc.base.adapter.CustomLoadMoreView;
import com.snc.base.adapter.animator.CustomAnimation2;
import com.snc.base.base.BaseActivity;
import com.snc.base.bean.AlarmBean;
import com.snc.base.http.api.AlarmListReqApi;
import com.snc.base.http.model.HttpListData;
import com.snc.base.router.RouterActivityPath;
import com.snc.base.utils.AppUtils;
import com.snc.base.utils.ClickEventUtils;
import com.snc.base.utils.LogUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 告警列表
*/
@Route(path = RouterActivityPath.Alarm.PAGER_ALARMLIST)
public class AlarmListActivity extends BaseActivity<ActivityAlarmListBinding> {
@Autowired(name = "chargePointId")
String chargePointId;
int page = 1;
int size = 10;
private final List<AlarmBean> list = new ArrayList<>();
AlarmListAdapter mAdapter;
@Override
protected int getContentLayoutId() {
return R.layout.activity_alarm_list;
}
@Override
protected void initListener() {
mBinding.topll.topback.setOnClickListener(this);
mBinding.topll.imgback.setOnClickListener(this);
}
@Override
protected void initData() {
mBinding.topll.toptitle.setText(R.string.alarm);
mBinding.recyclerView.setHasFixedSize(true);
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mBinding.recyclerView.addItemDecoration(new DividerItemDecoration(AppUtils.getContext(), DividerItemDecoration.VERTICAL));
mAdapter = new AlarmListAdapter(list);
mAdapter.setAnimationEnable(true);
mAdapter.setAnimationWithDefault(BaseQuickAdapter.AnimationType.ScaleIn);
mAdapter.setAdapterAnimation(new CustomAnimation2());
mAdapter.getLoadMoreModule().setLoadMoreView(new CustomLoadMoreView());
mBinding.recyclerView.setAdapter(mAdapter);
initRefreshLayout();
initLoadMore();
}
public void onResume() {
super.onResume();
// 进入页面,刷新数据
mBinding.swipeRefreshLayout.setRefreshing(true);
refresh();
}
private void initRefreshLayout() {
mBinding.swipeRefreshLayout.setColorSchemeColors(Color.rgb(47, 223, 189));
mBinding.swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refresh();
}
});
}
/**
* 初始化加载更多
*/
private void initLoadMore() {
mAdapter.getLoadMoreModule().setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
loadMore();
}
});
mAdapter.getLoadMoreModule().setAutoLoadMore(true);
//当自动加载开启,同时数据不满一屏时,是否继续执行自动加载更多(默认为true)
mAdapter.getLoadMoreModule().setEnableLoadMoreIfNotFullPage(false);
}
/**
* 刷新
*/
private void refresh() {
// 这里的作用是防止下拉刷新的时候还可以上拉加载
mAdapter.getLoadMoreModule().setEnableLoadMore(false);
page = 1;
getAlarmListReq();
}
/**
* 加载更多
*/
private void loadMore() {
getAlarmListReq();
}
@Override
public void onClick(View v) {
if (ClickEventUtils.isFastClick()) {
}
}
// @Override
// public void onCharacteristicChanged(String data, BluetoothGattCharacteristic characteristic) {
// LogUtils.ble("返回的UUid:" + characteristic.getUuid());
// LogUtils.ble("返回的蓝牙信息:" + data);
// }
//
// @Override
// public void onConnectionStateChange(Boolean state) {
// if (!state) {
// LogUtils.i("蓝牙断开");
// }
// }
//
// @Override
// public void onServicesDiscovered(List<BluetoothGattService> services) {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// serviceManager.clearServiceList();
// serviceManager.addlist(services);
// setMTU();
// }
// });
// }
@Override
public void onMessageReceived(String topic, String message) {
LogUtils.mqtt("返回的订阅信息topic:" + topic);
LogUtils.mqtt("返回的订阅信息message:" + message);
}
@Override
public void onNetworkStateChanged(String networkType) {
LogUtils.i("当前网络状态:" + networkType);
}
/**
* 获取告警列表
*/
public void getAlarmListReq() {
showLoading();
EasyHttp.post(this)
.api(new AlarmListReqApi()
.setChargePointId(chargePointId)
.setPage(page)
.setSize(size))
.request(new OnHttpListener<HttpListData<AlarmBean>>() {
@Override
public void onHttpSuccess(HttpListData<AlarmBean> result) {
hideLoading();
mBinding.swipeRefreshLayout.setRefreshing(false);
mAdapter.getLoadMoreModule().setEnableLoadMore(true);
if (page == 1) {
//如果是加载的第一页数据,用 setData()
mAdapter.setList(result.getList());
} else {
//不是第一页,则用add
mAdapter.addData(result.getList());
}
if (result.getList().size() < size) {
//如果不够一页,显示没有更多数据布局
mAdapter.getLoadMoreModule().loadMoreEnd();
} else {
mAdapter.getLoadMoreModule().loadMoreComplete();
}
page++;
}
@Override
public void onHttpFail(Throwable throwable) {
hideLoading();
mBinding.swipeRefreshLayout.setRefreshing(false);
mAdapter.getLoadMoreModule().setEnableLoadMore(true);
mAdapter.getLoadMoreModule().loadMoreFail();
}
});
}
}

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
tools:context="com.snc.alarm.ui.AlarmListActivity">
<include
android:id="@+id/topll"
layout="@layout/base_top" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topll"
app:layout_constraintVertical_bias="0.1"
app:layout_constraintWidth_percent="0.9">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:background="@color/itemhistory"
android:orientation="vertical"
app:cardBackgroundColor="@color/itemhistory"
app:cardCornerRadius="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/img"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="18dp"
android:background="@drawable/green_shape" />
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="@dimen/textsize20" />
</LinearLayout>
</androidx.cardview.widget.CardView>

@ -0,0 +1,17 @@
package com.snc.alarm;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

1
app/.gitignore vendored

@ -0,0 +1 @@
/build

Binary file not shown.

@ -0,0 +1,121 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
android {
namespace 'com.snc.evivecharger'
compileSdk rootProject.ext.android.compileSdk
defaultConfig {
applicationId rootProject.ext.android.applicationId
minSdk rootProject.ext.android.minSdk
targetSdk rootProject.ext.android.targetSdk
versionCode rootProject.ext.android.versionCode
versionName rootProject.ext.android.versionName
multiDexEnabled rootProject.ext.android.multiDexEnabled
//
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
buildFeatures {
//2 ViewBinding & DataBinding
dataBinding = true
viewBinding = true
}
// APK https://www.jianshu.com/p/a1f8e5896aa2
signingConfigs {
config {
storeFile file('EViveCharger.jks')
storePassword 'snc123456'
keyAlias 'snc'
keyPassword 'snc123456'
}
debug {
storeFile file('EViveCharger.jks')
storePassword 'snc123456'
keyAlias 'snc'
keyPassword 'snc123456'
}
}
buildTypes {
debug {
debuggable true
jniDebuggable true
//
shrinkResources false
//
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
// APK https://www.jianshu.com/p/a1f8e5896aa2
release {
debuggable false
jniDebuggable false
//
shrinkResources true
//
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
}
applicationVariants.all { variant ->
// Apk
variant.outputs.all { output ->
outputFileName = "EVive-Charger_" + variant.buildType.name + "_V" + variant.versionName + "-" + new Date().format('YYYYMMdd') + ".apk"
}
}
//
packagingOptions {
exclude 'META-INF/NOTICE.md'
exclude 'META-INF/LICENSE.md'
}
}
dependencies {
//宿
if (isModule.toBoolean()) {
//宿
implementation project(':lib_base')
} else {
api project(':lib_base')
implementation project(':login')
implementation project(':mian')
implementation project(':home')
implementation project(':history')
implementation project(':settings')
implementation project(':wifi')
implementation project(':web')
implementation project(':schedules')
implementation project(':alarm')
implementation project(':ble')
}
kapt 'com.alibaba:arouter-compiler:1.5.2'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

@ -0,0 +1,718 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#1.基本指令区
# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
-optimizationpasses 5
# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames
# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
# 指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers
# 不进行优化,建议使用此选项,
-dontoptimize
# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify 能够加快混淆速度
-dontpreverify
# 使我们的项目混淆后产生映射文件包含有类名->混淆后类名的映射关系
-verbose
# 使用printmapping指定映射文件的名称
-printmapping proguardMapping.txt
# 屏蔽警告
-ignorewarnings
# 指定混淆是采用的算法,后面的参数是一个过滤器这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*
# 保留Annotation不混淆
-keepattributes *Annotation*
# 避免混淆泛型
-keepattributes Signature
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
#2.默认保留区
# 保留我们使用的四大组件,自定义的Application等等这些类不被混淆
# 因为这些子类都有可能被外部调用
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
-keep public class com.google.vending.licensing.ILicensingService
# 保留support下的所有类及其内部类
-keep class android.support.** {*;}
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保留在Activity中的方法参数是view的方法,这样一来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
# 保留枚举类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 保留我们自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 保留R下面的资源
-keep class **.R$* {
*;
}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
# 避免layout中onclick方法(android:onclick="onClick")混淆
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
# webview
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.webView, jav.lang.String);
}
#在app中与HTML5的JavaScript的交互进行特殊处理
#我们需要确保这些js要调用的原生方法不能够被混淆,于是我们需要做如下处理:
#-keepclassmembers class com.XXX.XXX.JSInterface {
# <methods>;
#}
# AndroidX混淆
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**
-dontwarn androidx.**
#me.jessyan:autosize:1.1.2
-keep class me.jessyan.autosize.** { *; }
-keep interface me.jessyan.autosize.** { *; }
#com.hjq:xxpermissions:9.6
-dontwarn com.hjq.permissions.**
#com.ttcble.android:blebase
-keep class com.ble.** { *; }
-keep class com.ttcble.** { *; }
-keep interface com.ble.** { *; }
-keep interface com.ttcble.** { *; }
# EventBus
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties { *; }
# If you DO use SQLCipher:
-keep class org.greenrobot.greendao.database.SqlCipherEncryptedHelper { *; }
# If you do NOT use SQLCipher:
-dontwarn net.sqlcipher.database.**
# If you do NOT use RxJava:
-dontwarn rx.**
#com.jeremyliao:live-event-bus-x:1.7.3
-dontwarn com.jeremyliao.liveeventbus.**
-keep class com.jeremyliao.liveeventbus.** {* ; }
-keep class android.arch.lifecycle.* { *; }
-keep class android.arch.core.* { *; }
# for androidx:
-dontwarn com.jeremyliao.liveeventbus.*
-keep class com.jeremyliao.liveeventbus.** { *; }
-keep class androidx.lifecycle.* { *; }
-keep class androidx.arch.core.* { *; }
#org.greenrobot:greendao:3.3.0
-keep class org.greenrobot.greendao.**{*;}
-keep public interface org.greenrobot.greendao.**
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
-keep class net.sqlcipher.database.**{*;}
-keep public interface net.sqlcipher.database.**
-dontwarn net.sqlcipher.database.**
-dontwarn org.greenrobot.greendao.**
#org.litepal.guolindev:core
-keep class org.litepal.** {
*;
}
-keep class * extends org.litepal.crud.DataSupport {
*;
}
-keep class * extends org.litepal.crud.LitePalSupport {
*;
}
#阿里路由框架
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
-dontwarn javax.lang.model.element.**
# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现
# -keep class * implements com.alibaba.android.arouter.facade.template.IProvide
#微信
-keep class com.tencent.mm.opensdk.** {
*;
}
-keep class com.tencent.wxop.** {
*;
}
-keep class com.tencent.mm.sdk.** {
*;
}
#XHttp2
-keep class com.snc.net.model.** { *; }
-keep class com.snc.net.cache.model.** { *; }
-keep class com.snc.net.cache.stategy.**{*;}
-keep class com.snc.net.annotation.** { *; }
#okhttp
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-dontwarn javax.annotation.**
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Exceptions
# RxJava RxAndroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
#如果用到Gson解析包的,直接添加下面这几行就能成功混淆,不然会报错
-keepattributes Signature
-keep class com.google.gson.stream.** { *; }
-keepattributes EnclosingMethod
-keep class org.xz_sale.entity.**{*;}
-keep class com.google.gson.** {*;}
-keep class com.google.**{*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep public class cn.jzvd.JZMediaSystem {*; }
-keep public class cn.jzvd.demo.CustomMedia.CustomMedia {*; }
-keep public class cn.jzvd.demo.CustomMedia.JZMediaIjk {*; }
-keep public class cn.jzvd.demo.CustomMedia.JZMediaSystemAssertFolder {*; }
-keep class tv.danmaku.ijk.media.player.** {*; }
-dontwarn tv.danmaku.ijk.media.player.*
-keep interface tv.danmaku.ijk.media.player.** { *; }
#串口问题
-dontwarn com.kongqw.**
-keep class com.kongqw.**{*;}
#数据库
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties { *; }
# If you DO use SQLCipher:
-keep class org.greenrobot.greendao.database.SqlCipherEncryptedHelper { *; }
# If you do NOT use SQLCipher:
-dontwarn net.sqlcipher.database.**
# If you do NOT use RxJava:
-dontwarn rx.**
-keep class com.just.agentweb.** {
*;
}
-dontwarn com.just.agentweb.**
#GSYVideoPlayer
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.**
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.utils.**
-keep class tv.danmaku.ijk.** { *; }
-dontwarn tv.danmaku.ijk.**
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, java.lang.Boolean);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keep public class com.google.android.material.bottomnavigation.BottomNavigationView { *; }
-keep public class com.google.android.material.bottomnavigation.BottomNavigationMenuView { *; }
-keep public class com.google.android.material.bottomnavigation.BottomNavigationPresenter { *; }
-keep public class com.google.android.material.bottomnavigation.BottomNavigationItemView { *; }
# # 自己项目中定义的实体类
-keep class com.snc.database.bean.** { *; }
-keep class com.snc.base.bean.** { *; }
-keep class com.snc.repairshop.bean.** { *; }
-keep class com.snc.acdoc.bean.** { *; }
-keep class com.snc.language.bean.** { *; }
-keep class com.snc.technician.bean.** { *; }
-keep class com.snc.examination.bean.**{*;}
-keep class com.snc.systemsetting.bean.** { *; }
-keep class com.snc.base.view.** { *; }
-keep class com.snc.base.base.utils.** { *; }
-keep class com.snc.base.base.** { *; }
-keep class com.snc.base.dbmanager.**{*;}
-keep class com.snc.base.ble.**{*;}
-keep public class * extends com.snc.base.base.IModuleInit
#保留我们使用的四大组件,自定义的Application等等这些类不被混淆
# 因为这些子类都有可能被外部调用
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
# 保留support下的所有类及其内部类
-keep class android.support.** {*;}
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
# 保留R下面的资源
-keep class **.R$* {*;}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保留在Activity中的方法参数是view的方法,
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
# 保留枚举类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 保留我们自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**
-dontwarn androidx.**
#me.jessyan:autosize:1.1.2
-keep class me.jessyan.autosize.** { *; }
-keep interface me.jessyan.autosize.** { *; }
#com.hjq:xxpermissions:9.6
-dontwarn com.hjq.permissions.**
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties { *; }
# If you DO use SQLCipher:
-keep class org.greenrobot.greendao.database.SqlCipherEncryptedHelper { *; }
# If you do NOT use SQLCipher:
-dontwarn net.sqlcipher.database.**
# If you do NOT use RxJava:
-dontwarn rx.**
-dontwarn com.jeremyliao.liveeventbus.**
-keep class com.jeremyliao.liveeventbus.** { *; }
-keep class androidx.lifecycle.** { *; }
-keep class androidx.arch.core.** { *; }
-dontwarn com.kingja.loadsir.**
-keep class com.kingja.loadsir.** {*;}
-keep class com.tencent.** {*;}
-keep class com.tencent.mmkv.** {*;}
-keep class com.luck.picture.lib.** { *; }
# use Camerax
-keep class com.luck.lib.camerax.** { *; }
# use uCrop
-dontwarn com.yalantis.ucrop**
-keep class com.yalantis.ucrop** { *; }
-keep interface com.yalantis.ucrop** { *; }
# Fastjson 混淆规则
-keep public class com.alibaba.fastjson.JSON {
public static ** toJSONString(**);
public static ** parseObject(**);
public static ** parseArray(**);
public static ** parse(**);
}
-keep public class com.alibaba.fastjson.** {
public <init>(org.json.JSONObject);
}
-keep public class * implements com.alibaba.fastjson.serializer.ObjectSerializer {
public <init>();
}
-keep public class * implements com.alibaba.fastjson.parser.deserializer.ObjectDeserializer {
public <init>();
}
-keep class com.alibaba.fastjson.parser.ParserConfig {
public <init>();
public static void putDeserializer(java.lang.Class, com.alibaba.fastjson.parser.deserializer.ObjectDeserializer);
}
-keep class com.alibaba.fastjson.serializer.SerializeConfig {
public <init>();
public static void putSerializer(java.lang.Class, com.alibaba.fastjson.serializer.ObjectSerializer);
}
-keep class com.alibaba.fastjson.util.TypeUtils {
public static void register(java.lang.Class, java.lang.Class);
}
# 如果使用了AutoType的功能,需要保留下面的类不被混淆
-keepattributes Signature
-keepattributes *Annotation*
-keepclassmembers class * {
@com.alibaba.fastjson.annotation.JSONField <fields>;
@com.alibaba.fastjson.annotation.JSONType <fields>;
}
# 如果使用了enum类型的序列化,需要保留enum的名字
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 如果使用了ASM的ClassGenerator,需要保留下面的类不被混淆
-dontnote com.alibaba.fastjson.asm.**
-keep class com.alibaba.fastjson.asm.** { *; }
##Glide
-dontwarn com.bumptech.glide.**
-keep class com.bumptech.glide.**{*;}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.hjq.permissions.** {*;}
# 保护AndroidX和Jetpack依赖库中的类和成员
-keep class androidx.** { *; }
-keep interface androidx.** { *; }
-keep public class * extends androidx.**
-keep public class * extends androidx.appcompat.app.AppCompatActivity
-keep public class * extends androidx.fragment.app.Fragment
-keep public class * extends androidx.fragment.app.FragmentActivity
-keep public class * extends androidx.appcompat.app.ActionBarActivity
-keep public class * extends androidx.preference.Preference
-keep public class * extends androidx.viewpager.widget.ViewPager
-keep public class * extends androidx.viewpager2.widget.ViewPager2
-keep public class * extends androidx.recyclerview.widget.RecyclerView
-keep public class * extends androidx.coordinatorlayout.widget.CoordinatorLayout
-keep public class * extends androidx.appcompat.widget.Toolbar
-keep public class * extends androidx.drawerlayout.widget.DrawerLayout
-keep public class * extends androidx.constraintlayout.widget.ConstraintLayout
-keep public class com.google.android.material.** { *; }
# 保留 ViewBinding 相关类和方法
-keep class * implements androidx.viewbinding.ViewBinding {
*;
}
# 保留 LayoutInflater.inflate 方法,避免 NoSuchMethodException 异常
-keepclassmembers class * {
void inflate(android.view.LayoutInflater, android.view.ViewGroup, boolean);
}
# 保留基础 Fragment 类及其抽象方法
-keep class com.snc.base.base.BaseFragment {
public protected *;
private *;
}
# 保留 BaseFragment 中的 initListener initData 方法
-keepclassmembers class com.snc.base.base.BaseFragment {
void initListener();
void initData();
}
# 保留 NetworkMonitor 类及其方法和成员变量
-keep class com.snc.base.network.NetworkMonitor {
public protected *;
private *;
}
# 保留 TDialog.Builder 类及其方法和成员变量
-keep class com.yourpackage.TDialog$Builder {
public protected *;
private *;
}
# 保留 OnBindViewListener OnViewClickListener 接口及其实现类
-keep interface com.snc.base.dialog.listener.OnBindViewListener {
public protected *;
private *;
}
-keep public class * extends androidx.appcompat.app.AppCompatActivity
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# AgentWeb
-keep public class com.just.agentweb.** {
<fields>;
<methods>;
}
-keep public class androidx.** {
<fields>;
<methods>;
}
# OkHttp3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
# EasyHttp
-keep class com.hjq.http.** {*;}
# 必须要加上此规则,否则会导致泛型解析失败
-keep public class * implements com.hjq.http.listener.OnHttpListener {
*;
}
# 不混淆这个包下的类
-keep class com.snc.base.http.** {
<fields>;
}
-keep class javax.mail.**{*;}
-keep class javax.mail.internet.**{*;}
-keep class org.apache.commons.mail.**{*;}
-keep class javamail.** {*;}
-keep class javax.mail.** {*;}
-keep class javax.activation.** {*;}
-keep class com.sun.mail.dsn.** {*;}
-keep class com.sun.mail.handlers.** {*;}
-keep class com.sun.mail.smtp.** {*;}
-keep class com.sun.mail.util.** {*;}
-keep class mailcap.** {*;}
-keep class mimetypes.** {*;}
-keep class myjava.awt.datatransfer.** {*;}
-keep class org.apache.harmony.awt.** {*;}
-keep class org.apache.harmony.misc.** {*;}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,26 @@
package com.snc.evivecharger;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.snc.smartcharger", appContext.getPackageName());
}
}

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!--授予对照片和视频的部分访问权限-->
<!-- Devices running Android 12L (API level 32) or lower -->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />-->
<!-- To handle the reselection within the app on devices running Android 14
or higher if your app targets Android 14 (API level 34) or higher. -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<!--蓝牙权限-->
<!-- Request legacy Bluetooth permissions on older devices. -->
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!-- Needed only if your app looks for Bluetooth devices.
If your app doesn't use Bluetooth scan results to derive physical
location information, you can
<a href="#assert-never-for-location">strongly assert that your app
doesn't derive physical location</a>. -->
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<!-- Needed only if your app makes the device discoverable to Bluetooth
devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!-- Needed only if your app communicates with already-paired Bluetooth
devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!--您的应用需要标准蓝牙功能-->
<uses-feature
android:name="android.hardware.bluetooth"
android:required="true" />
<!--应用依赖于低功耗蓝牙-->
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<!--wifi权限-->
<!-- <uses-permission-->
<!-- android:name="android.permission.NEARBY_WIFI_DEVICES"-->
<!-- android:usesPermissionFlags="neverForLocation"-->
<!-- tools:targetApi="s" />-->
<!-- <uses-permission-->
<!-- android:name="android.permission.ACCESS_FINE_LOCATION"-->
<!-- android:maxSdkVersion="32" />-->
<!--网络状态权限-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- Android 6 ~ 12 使用定位权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--屏幕保持唤醒 不锁屏-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--Mqtt需要的权限高版本需要-->
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<!--前台服务也是为了Mqtt服务-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<application
android:name="com.snc.base.base.BaseApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/evive_charger_logo"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_config"
android:roundIcon="@drawable/evive_charger_logo"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:targetApi="31">
<!-- 华为第一次安装显示全屏显示问题-->
<meta-data
android:name="android.max_aspect"
android:value="2.4" />
<!-- Mqtt Service -->
<service
android:name="org.eclipse.paho.android.service.MqttService"
android:foregroundServiceType="dataSync" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths_public" />
</provider>
</application>
</manifest>

@ -0,0 +1,13 @@
package com.snc.evivecharger;
import com.snc.base.base.BaseApplication;
public class AppApplication extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
}
}

@ -0,0 +1,17 @@
package com.snc.evivecharger;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

1
ble/.gitignore vendored

@ -0,0 +1 @@
/build

@ -0,0 +1,32 @@
apply from: "../module.build.gradle"
apply plugin: 'org.jetbrains.kotlin.android'
android {
namespace 'com.snc.ble'
defaultConfig {
//使
if (isModule.toBoolean()) {
namespace 'com.snc.ble'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.activity:activity:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
kapt 'com.alibaba:arouter-compiler:1.5.2'
//宿
api project(':lib_base')
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,26 @@
package com.snc.ble;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.snc.ble", appContext.getPackageName());
}
}

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".ui.BlechargActivity"
android:exported="false"
android:configChanges="orientation|screenSize"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|adjustNothing|stateHidden" />
<activity
android:name=".ui.BleActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|adjustNothing|stateHidden" />
</application>
</manifest>

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!--授予对照片和视频的部分访问权限-->
<!-- Devices running Android 12L (API level 32) or lower -->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />-->
<!-- To handle the reselection within the app on devices running Android 14
or higher if your app targets Android 14 (API level 34) or higher. -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<!--蓝牙权限-->
<!-- Request legacy Bluetooth permissions on older devices. -->
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!-- Needed only if your app looks for Bluetooth devices.
If your app doesn't use Bluetooth scan results to derive physical
location information, you can
<a href="#assert-never-for-location">strongly assert that your app
doesn't derive physical location</a>. -->
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<!-- Needed only if your app makes the device discoverable to Bluetooth
devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!-- Needed only if your app communicates with already-paired Bluetooth
devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!--您的应用需要标准蓝牙功能-->
<uses-feature
android:name="android.hardware.bluetooth"
android:required="true" />
<!--应用依赖于低功耗蓝牙-->
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<!--wifi权限-->
<!-- <uses-permission-->
<!-- android:name="android.permission.NEARBY_WIFI_DEVICES"-->
<!-- android:usesPermissionFlags="neverForLocation"-->
<!-- tools:targetApi="s" />-->
<!-- <uses-permission-->
<!-- android:name="android.permission.ACCESS_FINE_LOCATION"-->
<!-- android:maxSdkVersion="32" />-->
<!--网络状态权限-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- Android 6 ~ 12 使用定位权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--屏幕保持唤醒 不锁屏-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--Mqtt需要的权限高版本需要-->
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<!--前台服务也是为了Mqtt服务-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<application
android:name="com.snc.base.debug.DebugApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".ui.BleActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|adjustNothing|stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.BlechargActivity"
android:exported="false"
android:configChanges="orientation|screenSize"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|adjustNothing|stateHidden" />
</application>
</manifest>

@ -0,0 +1,20 @@
package com.snc.ble;
import android.app.Application;
import com.snc.base.base.IModuleInit;
import com.snc.base.utils.LogUtils;
public class BleModuleInit implements IModuleInit {
@Override
public boolean onInitAhead(Application application) {
LogUtils.e("纯蓝牙模块 -- onInitAhead");
return false;
}
@Override
public boolean onInitLow(Application application) {
LogUtils.e("纯蓝牙模块 -- onInitLow");
return false;
}
}

@ -0,0 +1,25 @@
package com.snc.ble.adapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.module.LoadMoreModule;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.snc.base.ble.model.BleDevice;
import com.snc.ble.R;
import java.util.List;
public class BleDeviceAdapter extends BaseQuickAdapter<BleDevice, BaseViewHolder> implements LoadMoreModule {
public BleDeviceAdapter(@Nullable List<BleDevice> data) {
super(R.layout.item_ble_device, data);
}
@Override
protected void convert(@NonNull BaseViewHolder baseViewHolder, BleDevice bleDevice) {
baseViewHolder.setText(R.id.name, bleDevice.getRealName());
baseViewHolder.setText(R.id.mac, bleDevice.getMacAddress());
baseViewHolder.setVisible(R.id.imgconnect, bleDevice.getIsconnten());
}
}

@ -0,0 +1,135 @@
package com.snc.ble.bean;
public class BleBean {
private String Rsouce;
private String MessageId;
private String Cmd;
private String State;
private String Error;
private BleData data;
public String getRsouce() {
return Rsouce;
}
public void setRsouce(String rsouce) {
Rsouce = rsouce;
}
public String getMessageId() {
return MessageId;
}
public void setMessageId(String messageId) {
MessageId = messageId;
}
public String getCmd() {
return Cmd;
}
public void setCmd(String cmd) {
Cmd = cmd;
}
public String getState() {
return State;
}
public void setState(String state) {
State = state;
}
public String getError() {
return Error;
}
public void setError(String error) {
Error = error;
}
public BleData getData() {
return data;
}
public void setData(BleData data) {
this.data = data;
}
public class BleData {
private String ChargePointId;
private String Status;
private String Duration;
private String Voltage;
private String Current;
private String Power;
private String Energy;
public String getChargePointId() {
return ChargePointId;
}
public void setChargePointId(String chargePointId) {
ChargePointId = chargePointId;
}
public String getStatus() {
return Status;
}
public void setStatus(String status) {
Status = status;
}
public String getDuration() {
return Duration;
}
public void setDuration(String duration) {
Duration = duration;
}
public String getVoltage() {
return Voltage;
}
public void setVoltage(String voltage) {
Voltage = voltage;
}
public String getCurrent() {
return Current;
}
public void setCurrent(String current) {
Current = current;
}
public String getPower() {
return Power;
}
public void setPower(String power) {
Power = power;
}
public String getEnergy() {
return Energy;
}
public void setEnergy(String energy) {
Energy = energy;
}
}
}

@ -0,0 +1,41 @@
package com.snc.ble.bean;
public class SendBle {
private String Rsouce;
private String MessageId;
private String ble_cmd;
public SendBle(String rsouce, String messageId, String ble_cmd) {
this.Rsouce = rsouce;
this.MessageId = messageId;
this.ble_cmd = ble_cmd;
}
public String getRsouce() {
return Rsouce;
}
public void setRsouce(String rsouce) {
Rsouce = rsouce;
}
public String getMessageId() {
return MessageId;
}
public void setMessageId(String messageId) {
MessageId = messageId;
}
public String getBle_cmd() {
return ble_cmd;
}
public void setBle_cmd(String ble_cmd) {
this.ble_cmd = ble_cmd;
}
}

@ -0,0 +1,4 @@
package com.snc.ble.constant;
public class BleConstant {
}

@ -0,0 +1,484 @@
package com.snc.ble.ui;
import static com.snc.base.ble.constant.BleConstant.WRITE;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.ScanResult;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.View;
import android.widget.EditText;
import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemClickListener;
import com.chad.library.adapter.base.listener.OnLoadMoreListener;
import com.hjq.gson.factory.GsonFactory;
import com.hjq.http.EasyHttp;
import com.hjq.http.listener.OnHttpListener;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;
import com.snc.base.adapter.CustomLoadMoreView;
import com.snc.base.adapter.animator.CustomAnimation2;
import com.snc.base.base.AppManager;
import com.snc.base.base.BaseActivity;
import com.snc.base.bean.BleBean;
import com.snc.base.ble.callback.BleMtuMsgCallback;
import com.snc.base.ble.callback.BleScanCallback;
import com.snc.base.ble.callback.ReceiverCallback;
import com.snc.base.ble.constant.BleConstant;
import com.snc.base.ble.model.BleDevice;
import com.snc.base.ble.receiver.ScanReceiver;
import com.snc.base.ble.utils.BleHandleUtils;
import com.snc.base.constant.Constant;
import com.snc.base.dialog.TDialog;
import com.snc.base.dialog.base.BindViewHolder;
import com.snc.base.dialog.listener.OnViewClickListener;
import com.snc.base.http.api.BindChargePointReqApi;
import com.snc.base.http.exception.FailedException;
import com.snc.base.http.exception.RejectedException;
import com.snc.base.http.exception.TokenException;
import com.snc.base.http.model.BaseBean;
import com.snc.base.http.model.HttpData;
import com.snc.base.network.NetworkMonitor;
import com.snc.base.router.RouterActivityPath;
import com.snc.base.utils.BluetoothUtils;
import com.snc.base.utils.CacheUtil;
import com.snc.base.utils.ClickEventUtils;
import com.snc.base.utils.LogUtils;
import com.snc.ble.R;
import com.snc.ble.adapter.BleDeviceAdapter;
import com.snc.ble.databinding.ActivityBleBinding;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Route(path = RouterActivityPath.Ble.PAGER_BLE)
public class BleActivity extends BaseActivity<ActivityBleBinding> implements BleScanCallback, ReceiverCallback {
ArrayList<BleDevice> list = new ArrayList<>();
BleDeviceAdapter mAdapter;
ScanReceiver scanReceiver;
/***
* 蓝牙设备没有注册等待收到蓝牙的相应信息在进行跳转
*/
private int BleRegSts;
/***
* 蓝牙基本信息
*/
private BleBean mbleBean = null;
/***
* 当前选中的设备
*/
private BleDevice bleDevice;
/**
* 蓝牙跳转使用原来的跳转方式过时了
*/
private ActivityResultLauncher<Intent> bluetoothActivityResultLauncher;
@Override
protected int getContentLayoutId() {
return R.layout.activity_ble;
}
@Override
protected void initListener() {
mBinding.topll.topback.setOnClickListener(this);
mBinding.topll.topback.setVisibility(View.GONE);
mBinding.topll.imgback.setOnClickListener(this);
}
protected IntentFilter makeFilter() {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
return filter;
}
@Override
protected void initData() {
mBinding.topll.toptitle.setText(R.string.pair_devices);
mBinding.recyclerView.setHasFixedSize(true);
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mBinding.recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
mAdapter = new BleDeviceAdapter(list);
mAdapter.setAnimationEnable(true);
mAdapter.setAnimationWithDefault(BaseQuickAdapter.AnimationType.ScaleIn);
mAdapter.setAdapterAnimation(new CustomAnimation2());
mAdapter.getLoadMoreModule().setLoadMoreView(new CustomLoadMoreView());
mBinding.recyclerView.setAdapter(mAdapter);
initRefreshLayout();
initLoadMore();
mAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
if (ClickEventUtils.isFastClick()) {
// if (bleCore.isScanning()) {
// bleCore.stopScan();
// }
// bleDevice = mAdapter.getItem(position);
// bleConnet(bleDevice);
}
}
});
//设置扫描回调
// if (BleHandleUtils.INSTANCE.isOpenBluetooth(this)) {
// bleCore.setPhyScanCallback(this);
// }
scanReceiver = new ScanReceiver();
scanReceiver.setCallback(this);
LocalBroadcastManager.getInstance(this).registerReceiver(new ScanReceiver(), makeFilter());
// 初始化 ActivityResultLauncher
bluetoothActivityResultLauncher = createActivityResultLauncher();
BlePermissions();
}
private void initRefreshLayout() {
mBinding.swipeRefreshLayout.setColorSchemeColors(Color.rgb(47, 223, 189));
mBinding.swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refresh();
}
});
}
/**
* 初始化加载更多
*/
private void initLoadMore() {
mAdapter.getLoadMoreModule().setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
loadMore();
}
});
// mAdapter.getLoadMoreModule().setAutoLoadMore(true);
//当自动加载开启,同时数据不满一屏时,是否继续执行自动加载更多(默认为true)
mAdapter.getLoadMoreModule().setEnableLoadMoreIfNotFullPage(false);
}
/**
* 刷新
*/
private void refresh() {
mBinding.swipeRefreshLayout.setRefreshing(false);
// 进入页面,刷新数据
blestopScan();
}
/**
* 加载更多
*/
private void loadMore() {
blestopScan();
}
private void BlePermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
XXPermissions.with(this)
.permission(Permission.SCHEDULE_EXACT_ALARM)
.permission(Permission.BLUETOOTH_SCAN)
.permission(Permission.BLUETOOTH_CONNECT)
.permission(Permission.BLUETOOTH_ADVERTISE).request(new OnPermissionCallback() {
@Override
public void onGranted(@NonNull List<String> permissions, boolean all) {
if (all) {
LogUtils.e("权限处理完了");
if (!BluetoothUtils.isBluetoothEnabled(BleActivity.this)) {
enableBluetooth();
} else {
refresh();
}
}
}
@Override
public void onDenied(@NonNull List<String> permissions, boolean never) {
if (never) {
LogUtils.e("权限部分处理");
}
}
});
} else {
XXPermissions.with(this)
.permission(Permission.ACCESS_FINE_LOCATION,
Permission.ACCESS_COARSE_LOCATION).request(new OnPermissionCallback() {
@Override
public void onGranted(@NonNull List<String> permissions, boolean all) {
if (all) {
LogUtils.e("权限处理完了");
if (!BluetoothUtils.isBluetoothEnabled(BleActivity.this)) {
enableBluetooth();
} else {
refresh();
}
}
}
@Override
public void onDenied(@NonNull List<String> permissions, boolean never) {
if (never) {
LogUtils.e("权限部分处理");
}
}
});
}
}
/**
* 蓝牙搜索并且10秒后关闭蓝牙搜索
*/
private void blestopScan() {
LogUtils.e("蓝牙开始搜索");
// bleCore.disconnect();
// if (!bleCore.isScanning())
// bleCore.startScan();
// // 使用 Handler 延迟执行数据更新操作
// new Handler(Looper.getMainLooper()).postDelayed(() -> {
// if (bleCore.isScanning()) {
// bleCore.stopScan();
// }
// }, 10000); // 10秒后执行
}
@Override
public void onClick(View v) {
if (ClickEventUtils.isFastClick()) {
if (v.getId() == R.id.topback || v.getId() == R.id.imgback) {
AppManager.getAppManager().finishActivity();
}
}
}
// @Override
// public void onConnectionStateChange(Boolean state) {
// if (!state) {
// LogUtils.e("蓝牙断开");
// }
// }
//
// @Override
// public void onServicesDiscovered(List<BluetoothGattService> services) {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// serviceManager.clearServiceList();
// serviceManager.addlist(services);
// setMTU(512);
// }
// });
// }
/**
* 设置MTU
*/
// private void setMTU(int mtu) {
// bleCore.requestMtu(mtu, new BleMtuMsgCallback<BleDevice>() {
// @Override
// public void onMtuSuccess(@NonNull BluetoothGatt gatt, int mtu, int status) {
// LogUtils.e("onMtuSuccess-------------" + "mtu---------" + mtu);
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// belSetALLNotify(serviceManager.getServiceList().get(2).getCharacteristics());
// }
// });
// }
//
// @Override
// public void onMtuFailed(@NonNull BluetoothGatt gatt, int mtu, int status) {
// LogUtils.e("onMtuFailed-------------" + "status---------" + status);
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// showMsg("Ble set Mtufailed");
// }
// });
//
// }
// });
// }
@Override
public void onScanResult(@NonNull ScanResult result) {
// 过滤空设备名
if (result.getScanRecord().getDeviceName() == null ||
result.getScanRecord().getDeviceName().isEmpty() ||
!result.getScanRecord().getDeviceName().startsWith("SVP")) {
return;
}
// 设备名称
String realName = result.getScanRecord().getDeviceName();
if (realName == null || realName.isEmpty()) {
realName = BleConstant.UNKNOWN_DEVICE;
}
BleDevice bleDevice = new BleDevice(
realName,
result.getDevice().getAddress(),
result.getRssi(),
result.getDevice(), null
, false
);
LogUtils.e("搜索到" + bleDevice.getRealName());
if (CacheUtil.getBleListImei() != null) {
for (String blemac : CacheUtil.getBleListImei()) {
if (blemac.equals(bleDevice.getMacAddress())) {
bleDevice.setIsconnten(true);
}
}
}
if (list.isEmpty()) {
list.add(bleDevice);
} else {
int index = BleHandleUtils.INSTANCE.findIndex(bleDevice, list);
if (index == -1) {
// 添加新设备
list.add(bleDevice);
} else {
// 更新已有设备的rssi
list.get(index).setRssi(bleDevice.getRssi());
}
}
handleScanResult(list);
}
/**
* 处理蓝牙扫描结果
*/
private void handleScanResult(List<BleDevice> scanData) {
LogUtils.e("handleScanResult-----scanData.size()" + "------------" + scanData.size());
mBinding.swipeRefreshLayout.setRefreshing(false);
mAdapter.getLoadMoreModule().setEnableLoadMore(true);
if (!scanData.isEmpty()) {
mAdapter.setList(scanData);
}
mAdapter.getLoadMoreModule().loadMoreEnd();
}
@Override
public void bluetoothClose() {
//页面停止时停止扫描
// if (bleCore.isScanning()) {
// bleCore.stopScan();
// }
}
@Override
public void locationClose() {
//位置关闭时停止扫描
// if (bleCore.isScanning()) {
// bleCore.stopScan();
// }
}
@Override
public void onBatchScanResults(@NonNull List<ScanResult> results) {
LogUtils.e("搜索完成" + results.toString());
}
@Override
public void onScanFailed(@NonNull String failed) {
}
// @Override
// public void onCharacteristicChanged(String data, BluetoothGattCharacteristic characteristic) {
// try {
// LogUtils.ble("返回的UUid:" + characteristic.getUuid());
// LogUtils.ble("返回的蓝牙信息:" + data);
// startActivity(new Intent(this,BlechargActivity.class));
//// ARouter.getInstance().build(RouterActivityPath.Ble.PAGER_BLECHARG)
//// .navigation();
// } catch (Exception e) {
// LogUtils.e("报错:" + e.toString());
// }
//
// }
@Override
public void onMessageReceived(String topic, String message) {
LogUtils.mqtt("返回的订阅信息topic:" + topic);
LogUtils.mqtt("返回的订阅信息message:" + message);
}
@Override
public void onNetworkStateChanged(String networkType) {
LogUtils.i("当前网络状态:" + networkType);
}
/**
* 创建一个ActivityResultLauncher
*
* @return
*/
private ActivityResultLauncher<Intent> createActivityResultLauncher() {
return registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
LogUtils.e("用户同意打开蓝牙打开蓝牙");
refresh();
} else {
// 用户拒绝打开蓝牙
LogUtils.e("用户拒绝打开蓝牙");
}
}
});
}
/**
* 打开当前手机蓝牙
*/
private void enableBluetooth() {
if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
Intent enableBluetoothIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
bluetoothActivityResultLauncher.launch(enableBluetoothIntent);
}
}
}

@ -0,0 +1,106 @@
package com.snc.ble.ui;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.os.Bundle;
import android.view.View;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.google.gson.Gson;
import com.hjq.gson.factory.GsonFactory;
import com.snc.base.base.BaseActivity;
import com.snc.base.bean.BleChargeNetwork;
import com.snc.base.bean.BleFirmwareStatusNotification;
import com.snc.base.bean.BleMeterValues;
import com.snc.base.bean.BleStatusNotification;
import com.snc.base.bean.BleTransactionDuration;
import com.snc.base.bean.BleUpdateFirmware;
import com.snc.base.ble.JsonHandleUtils;
import com.snc.base.constant.Constant;
import com.snc.base.mqtt.MqttManager;
import com.snc.base.network.NetworkMonitor;
import com.snc.base.router.RouterActivityPath;
import com.snc.base.utils.LogUtils;
import com.snc.base.utils.ResUtils;
import com.snc.ble.R;
import com.snc.ble.bean.BleBean;
import com.snc.ble.bean.SendBle;
import com.snc.ble.databinding.ActivityBlechargBinding;
import java.util.List;
import java.util.UUID;
@Route(path = RouterActivityPath.Ble.PAGER_BLECHARG)
public class BlechargActivity extends BaseActivity<ActivityBlechargBinding> {
@Override
protected int getContentLayoutId() {
return R.layout.activity_blecharg;
}
@Override
protected void initListener() {
mBinding.start.setOnClickListener(this);
mBinding.stop.setOnClickListener(this);
}
@Override
protected void initData() {
mBinding.topll.toptitle.setText("Ble");
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.start) {
// SendBle sendBle = new SendBle(2 + "", System.currentTimeMillis() + "", "start");
// sendBluetoothMsg(0, GsonFactory.getSingletonGson().toJson(sendBle), serviceManager.getServiceList().get(2).getCharacteristics());
} else if (v.getId() == R.id.stop) {
// SendBle sendBle = new SendBle(2 + "", System.currentTimeMillis() + "", "stop");
// sendBluetoothMsg(0, GsonFactory.getSingletonGson().toJson(sendBle), serviceManager.getServiceList().get(2).getCharacteristics());
}
}
// @Override
// public void onCharacteristicChanged(String data, BluetoothGattCharacteristic characteristic) {
// try {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// LogUtils.ble("返回的蓝牙UUid:" + characteristic.getUuid());
// LogUtils.ble("返回的蓝牙信息:" + data);
// BleBean bean = GsonFactory.getSingletonGson().fromJson(data, BleBean.class);
// mBinding.charginname.setText(bean.getState());
// }
// });
// } catch (Exception e) {
// LogUtils.e("报错:" + e.toString());
// }
// }
//
// @Override
// public void onConnectionStateChange(Boolean state) {
//
// }
//
// @Override
// public void onServicesDiscovered(List<BluetoothGattService> services) {
//
// }
@Override
public void onMessageReceived(String topic, String message) {
}
@Override
public void onNetworkStateChanged(String networkType) {
}
}

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
tools:context=".ui.BleActivity">
<include
android:id="@+id/topll"
layout="@layout/base_top" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topll"
app:layout_constraintVertical_bias="0.1"
app:layout_constraintWidth_percent="0.9">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
tools:context=".ui.BlechargActivity">
<include
android:id="@+id/topll"
layout="@layout/base_top" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/button_grey_5"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topll"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintWidth_percent="0.9">
<TextView
android:id="@+id/charginname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/color_64696E"
android:textSize="@dimen/textsize18"
tools:text="@string/available" />
<TextView
android:id="@+id/chargingTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="@dimen/textsize18"
tools:text="@string/twobars" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/ChargingVoltage"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="26dp"
android:layout_weight="1"
android:gravity="right"
android:text="@string/twobars"
android:textColor="@color/white"
android:textSize="@dimen/textsize18"
tools:text="@string/twobars" />
<TextView
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#D7D7D7" />
<TextView
android:id="@+id/ChargingCurrent"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="26dp"
android:layout_marginRight="26dp"
android:text="@string/twobars"
android:textColor="@color/white"
android:textSize="@dimen/textsize18"
tools:text="@string/twobars" />
<TextView
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#D7D7D7" />
<TextView
android:id="@+id/ChargingPower"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="26dp"
android:layout_weight="1"
android:text="@string/twobars"
android:textColor="@color/white"
android:textSize="@dimen/textsize18"
tools:text="@string/twobars" />
</LinearLayout>
<Button
android:id="@+id/start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="蓝牙开启" />
<Button
android:id="@+id/stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="蓝牙停止" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/addble"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginBottom="10dp"
android:background="@drawable/button_grey_5">
<ImageView
android:id="@+id/imageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="15dp"
android:src="@drawable/device_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageView"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.8">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="@string/ev_charger"
android:textColor="@color/white"
android:textSize="@dimen/textsize22"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageView"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/mac"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="@string/_3439354d0e36313133317271"
android:textColor="@color/white"
android:textSize="@dimen/textsize14"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageView"
app:layout_constraintTop_toBottomOf="@+id/name" />
</LinearLayout>
<ImageView
android:id="@+id/imgconnect"
android:layout_width="13dp"
android:layout_height="10dp"
android:layout_marginEnd="15dp"
android:src="@drawable/green_check"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,17 @@
package com.snc.ble;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

@ -0,0 +1,29 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply from: "versions.gradle"
buildscript {
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
}
dependencies {
classpath 'com.android.tools.build:gradle:8.4.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

@ -0,0 +1,26 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
#AGP 8.0 ???? R8 ?????
android.enableR8.fullMode=false
#AGP 8.0 ?????????????? R ?
android.nonTransitiveRClass=false
# isModule“集成开发模式”和“组件开发模式”的切换开关
isModule=false
#isModule=true

Binary file not shown.

@ -0,0 +1,6 @@
#Mon Jun 03 12:09:18 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=file:///D:/gradle/gradle-8.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
gradlew vendored

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

@ -0,0 +1 @@
/build

@ -0,0 +1,27 @@
apply from: "../module.build.gradle"
android {
namespace 'com.snc.history'
defaultConfig {
//使
if (isModule.toBoolean()) {
namespace 'com.snc.history'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
kapt 'com.alibaba:arouter-compiler:1.5.2'
//宿
api project(':lib_base')
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,26 @@
package com.snc.history;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.snc.history", appContext.getPackageName());
}
}

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application />
</manifest>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name="com.snc.base.debug.DebugApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
</manifest>

@ -0,0 +1,20 @@
package com.snc.history;
import android.app.Application;
import com.snc.base.base.IModuleInit;
import com.snc.base.utils.LogUtils;
public class HistoryModuleInit implements IModuleInit {
@Override
public boolean onInitAhead(Application application) {
LogUtils.e("历史模块 -- onInitAhead");
return false;
}
@Override
public boolean onInitLow(Application application) {
LogUtils.e("历史模块 -- onInitLow");
return false;
}
}

@ -0,0 +1,28 @@
package com.snc.history.adapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.module.LoadMoreModule;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.snc.base.http.bean.HistoryBean;
import com.snc.base.utils.ResUtils;
import com.snc.history.R;
import java.util.List;
public class HistoryAdapter extends BaseQuickAdapter<HistoryBean, BaseViewHolder> implements LoadMoreModule {
public HistoryAdapter(@Nullable List<HistoryBean> data) {
super(R.layout.item_history, data);
}
@Override
protected void convert(@NonNull BaseViewHolder baseViewHolder, HistoryBean historyBean) {
baseViewHolder.setText(R.id.tvHistoryDate, historyBean.getDateStr());
baseViewHolder.setText(R.id.tvHistoryName, historyBean.getChargePointId());
baseViewHolder.setText(R.id.tvHistoryStartTime, historyBean.getStartTimeStr());
baseViewHolder.setText(R.id.tvHistoryDurationTime, historyBean.getChargeTime());
baseViewHolder.setText(R.id.tvHistoryUsage, historyBean.getMeterPower() + ResUtils.getString(com.snc.base.R.string.kwh));
}
}

@ -0,0 +1,157 @@
package com.snc.history.ui;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.graphics.Color;
import android.view.View;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnLoadMoreListener;
import com.hjq.http.EasyHttp;
import com.hjq.http.listener.OnHttpListener;
import com.snc.base.adapter.animator.CustomAnimation2;
import com.snc.base.base.BaseFragment;
import com.snc.base.http.api.ChargingHistoryReqApi;
import com.snc.base.http.model.HttpListData;
import com.snc.base.router.RouterFragmentPath;
import com.snc.base.utils.AppUtils;
import com.snc.base.utils.ClickEventUtils;
import com.snc.base.utils.LogUtils;
import com.snc.history.adapter.HistoryAdapter;
import com.snc.history.databinding.FragmentHistoryBinding;
import com.snc.base.http.bean.HistoryBean;
import com.snc.base.adapter.CustomLoadMoreView;
import java.util.ArrayList;
import java.util.List;
/**
* 历史记录
*/
@Route(path = RouterFragmentPath.History.PAGER_HISTORY)
public class HistoryFragment extends BaseFragment<FragmentHistoryBinding> {
private final List<HistoryBean> list = new ArrayList<>();
HistoryAdapter mAdapter;
int page = 1;
int size = 10;
@Override
protected void initListener() {
}
@Override
protected void initData() {
binding.recyclerView.setHasFixedSize(true);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recyclerView.addItemDecoration(new DividerItemDecoration(AppUtils.getContext(), DividerItemDecoration.VERTICAL));
mAdapter = new HistoryAdapter(list);
mAdapter.setAnimationEnable(true);
mAdapter.setAnimationWithDefault(BaseQuickAdapter.AnimationType.ScaleIn);
mAdapter.setAdapterAnimation(new CustomAnimation2());
mAdapter.getLoadMoreModule().setLoadMoreView(new CustomLoadMoreView());
binding.recyclerView.setAdapter(mAdapter);
initRefreshLayout();
initLoadMore();
}
@Override
public void onResume() {
super.onResume();
// 进入页面,刷新数据
binding.swipeRefreshLayout.setRefreshing(true);
refresh();
}
private void initRefreshLayout() {
binding.swipeRefreshLayout.setColorSchemeColors(Color.rgb(47, 223, 189));
binding.swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refresh();
}
});
}
/**
* 初始化加载更多
*/
private void initLoadMore() {
mAdapter.getLoadMoreModule().setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
loadMore();
}
});
mAdapter.getLoadMoreModule().setAutoLoadMore(true);
//当自动加载开启,同时数据不满一屏时,是否继续执行自动加载更多(默认为true)
mAdapter.getLoadMoreModule().setEnableLoadMoreIfNotFullPage(false);
}
/**
* 刷新
*/
private void refresh() {
// 这里的作用是防止下拉刷新的时候还可以上拉加载
mAdapter.getLoadMoreModule().setEnableLoadMore(false);
page = 1;
chargingHistoryReq();
}
/**
* 加载更多
*/
private void loadMore() {
chargingHistoryReq();
}
@Override
public void onClick(View v) {
if (ClickEventUtils.isFastClick()){}
}
private void chargingHistoryReq() {
EasyHttp.post(this)
.api(new ChargingHistoryReqApi()
.setPage(page)
.setSize(size))
.request(new OnHttpListener<HttpListData<HistoryBean>>() {
@Override
public void onHttpSuccess(HttpListData<HistoryBean> result) {
binding.swipeRefreshLayout.setRefreshing(false);
mAdapter.getLoadMoreModule().setEnableLoadMore(true);
if (page == 1) {
//如果是加载的第一页数据,用 setData()
mAdapter.setList(result.getList());
} else {
//不是第一页,则用add
mAdapter.addData(result.getList());
}
if (result.getList().size() < size) {
//如果不够一页,显示没有更多数据布局
mAdapter.getLoadMoreModule().loadMoreEnd();
} else {
mAdapter.getLoadMoreModule().loadMoreComplete();
}
page++;
}
@Override
public void onHttpFail(Throwable throwable) {
binding.swipeRefreshLayout.setRefreshing(false);
mAdapter.getLoadMoreModule().setEnableLoadMore(true);
mAdapter.getLoadMoreModule().loadMoreFail();
}
});
}
@Override
public void onNetworkStateChanged(String networkType) {
LogUtils.i("当前网络状态:" + networkType);
}
}

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="@dimen/topbar_height"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="History"
android:textColor="@color/white"
android:textSize="@dimen/topbar_title_textsize" />
</LinearLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2"
app:layout_constraintVertical_bias="0">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/loading_view"
layout="@layout/custom_loading_view"
android:visibility="gone" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

@ -0,0 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:orientation="vertical"
android:background="@color/itemhistory"
app:cardBackgroundColor="@color/itemhistory"
app:cardCornerRadius="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tvHistoryDate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:text="@string/dec_25_2023"
android:textColor="@color/white"
android:textSize="@dimen/textsize20">
</TextView>
<TextView
android:id="@+id/tvHistoryName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_weight="1"
android:gravity="right"
android:text="@string/ev_charger_1"
android:textColor="@color/white"
android:textSize="@dimen/textsize15">
</TextView>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
android:background="#ff393d41" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:text="@string/start_time"
android:textColor="@color/white"
android:textSize="@dimen/textsize14">
</TextView>
<TextView
android:id="@+id/tvHistoryStartTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_weight="1"
android:gravity="right"
android:text="@string/_9_18am"
android:textColor="@color/white"
android:textSize="@dimen/textsize14" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:text="@string/charging_time"
android:textColor="@color/white"
android:textSize="@dimen/textsize14">
</TextView>
<TextView
android:id="@+id/tvHistoryDurationTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_weight="1"
android:gravity="right"
android:text="@string/_1h36_min"
android:textColor="@color/white"
android:textSize="@dimen/textsize14" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:text="@string/usage"
android:textColor="@color/white"
android:textSize="@dimen/textsize14">
</TextView>
<TextView
android:id="@+id/tvHistoryUsage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_weight="1"
android:gravity="right"
android:text="@string/_0_09_kwh"
android:textColor="@color/white"
android:textSize="@dimen/textsize14" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

@ -0,0 +1,17 @@
package com.snc.history;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

1
home/.gitignore vendored

@ -0,0 +1 @@
/build

@ -0,0 +1,27 @@
apply from: "../module.build.gradle"
android {
namespace 'com.snc.home'
defaultConfig {
//使
if (isModule.toBoolean()) {
namespace 'com.snc.home'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
kapt 'com.alibaba:arouter-compiler:1.5.2'
//宿
api project(':lib_base')
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,26 @@
package com.snc.home;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.snc.home", appContext.getPackageName());
}
}

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application />
</manifest>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name="com.snc.base.debug.DebugApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
</manifest>

@ -0,0 +1,20 @@
package com.snc.home;
import android.app.Application;
import com.snc.base.base.IModuleInit;
import com.snc.base.utils.LogUtils;
public class HomeModuleInit implements IModuleInit {
@Override
public boolean onInitAhead(Application application) {
LogUtils.e("首页模块 -- onInitAhead");
return false;
}
@Override
public boolean onInitLow(Application application) {
LogUtils.e("首页模块 -- onInitLow");
return false;
}
}

@ -0,0 +1,50 @@
package com.snc.home.adapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.module.LoadMoreModule;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.snc.base.http.bean.DeviceListbean;
import com.snc.base.utils.ResUtils;
import com.snc.home.R;
import java.util.List;
public class DeviceListAdapter extends BaseQuickAdapter<DeviceListbean, BaseViewHolder> implements LoadMoreModule {
public DeviceListAdapter(@Nullable List<DeviceListbean> data) {
super(R.layout.item_home_device_list, data);
}
@Override
protected void convert(@NonNull BaseViewHolder baseViewHolder, DeviceListbean deviceListbean) {
if (deviceListbean.getDevice() != null) {
if (deviceListbean.getDevice().getConnector() != null && deviceListbean.getDevice().getConnector().getConnectorStatus().equals(ResUtils.getString(R.string.charging))) {
baseViewHolder.setImageResource(R.id.img, R.drawable.switch_on);
baseViewHolder.setText(R.id.state, deviceListbean.getDevice().getConnector().getConnectorStatus());
baseViewHolder.setTextColor(R.id.state, ResUtils.getColor(R.color.green));
baseViewHolder.setText(R.id.time, deviceListbean.getDevice().getDuration());
baseViewHolder.setText(R.id.power, deviceListbean.getDevice().getChargingPower());
baseViewHolder.setText(R.id.Current, deviceListbean.getDevice().getChargingCurrent());
} else {
baseViewHolder.setImageResource(R.id.img, R.drawable.switch_off);
if (deviceListbean.getDevice().getConnector() != null && deviceListbean.getDevice().getConnector().getConnectorStatus().equals(ResUtils.getString(R.string.preparing))) {
baseViewHolder.setText(R.id.state, deviceListbean.getDevice().getConnector().getConnectorStatus());
baseViewHolder.setTextColor(R.id.state, ResUtils.getColor(R.color.green));
} else {
baseViewHolder.setText(R.id.state, deviceListbean.getDevice().getConnector().getConnectorStatus());
baseViewHolder.setTextColor(R.id.state, ResUtils.getColor(com.snc.base.R.color.color_64696E));
}
baseViewHolder.setText(R.id.time, ResUtils.getString(com.snc.base.R.string.twobars));
baseViewHolder.setText(R.id.power, ResUtils.getString(R.string.twobars) + ResUtils.getString(R.string.kwh));
baseViewHolder.setText(R.id.Current, ResUtils.getString(R.string.twobars) + ResUtils.getString(R.string.a));
}
if (deviceListbean.getDevice().getErrorCode() != null && !deviceListbean.getDevice().getErrorCode().equals(ResUtils.getString(R.string.noerror))) {
baseViewHolder.setVisible(R.id.imgbell, true);
}
baseViewHolder.setText(R.id.name, deviceListbean.getDevice().getDeviceName());
}
}
}

@ -0,0 +1,549 @@
package com.snc.home.ui;
import static com.luck.picture.lib.thread.PictureThreadUtils.runOnUiThread;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemChildClickListener;
import com.chad.library.adapter.base.listener.OnItemClickListener;
import com.chad.library.adapter.base.listener.OnLoadMoreListener;
import com.google.gson.Gson;
import com.hjq.gson.factory.GsonFactory;
import com.hjq.http.EasyHttp;
import com.hjq.http.listener.OnHttpListener;
import com.snc.base.adapter.CustomLoadMoreView;
import com.snc.base.adapter.animator.CustomAnimation2;
import com.snc.base.base.BaseFragment;
import com.snc.base.bean.BleChargeNetwork;
import com.snc.base.bean.BleFirmwareStatusNotification;
import com.snc.base.bean.BleMeterValues;
import com.snc.base.bean.BleStatusNotification;
import com.snc.base.bean.BleTransactionDuration;
import com.snc.base.bean.BleUpdateFirmware;
import com.snc.base.http.bean.DeviceListbean;
import com.snc.base.bean.NetChargeNetwork;
import com.snc.base.bean.NetFirmwareStatusNotification;
import com.snc.base.bean.NetMessage;
import com.snc.base.bean.NetMeterValues;
import com.snc.base.bean.NetStatusNotification;
import com.snc.base.bean.NetTransactionDuration;
import com.snc.base.bean.NetUpdateFirmware;
import com.snc.base.http.api.DeviceListApi;
import com.snc.base.http.api.TriggerMessageReqApi;
import com.snc.base.http.model.BaseBean;
import com.snc.base.http.model.HttpData;
import com.snc.base.http.model.HttpListData;
import com.snc.base.mqtt.MqttManager;
import com.snc.base.mqtt.MqttMessageListener;
import com.snc.base.network.NetworkMonitor;
import com.snc.base.router.RouterActivityPath;
import com.snc.base.router.RouterFragmentPath;
import com.snc.base.utils.AppUtils;
import com.snc.base.utils.CacheUtil;
import com.snc.base.utils.ClickEventUtils;
import com.snc.base.utils.LogUtils;
import com.snc.base.utils.ResUtils;
import com.snc.base.utils.StringUtils;
import com.snc.base.viewmodel.BleDataViewModel;
import com.snc.home.R;
import com.snc.home.adapter.DeviceListAdapter;
import com.snc.home.databinding.FragmentHomeBinding;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Route(path = RouterFragmentPath.Home.PAGER_HOME)
public class HomeFragment extends BaseFragment<FragmentHomeBinding> implements MqttMessageListener {
List<DeviceListbean> mDatas = new ArrayList<>();
DeviceListAdapter mAdapter;
int page = 1;
int size = 10;
private BleDataViewModel bleDataViewModel;
@Override
protected void initListener() {
}
@Override
protected void initData() {
binding.recyclerView.setHasFixedSize(true);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recyclerView.addItemDecoration(new DividerItemDecoration(AppUtils.getContext(), DividerItemDecoration.VERTICAL));
mAdapter = new DeviceListAdapter(mDatas);
mAdapter.setAnimationEnable(true);
mAdapter.setAnimationWithDefault(BaseQuickAdapter.AnimationType.ScaleIn);
mAdapter.setAdapterAnimation(new CustomAnimation2());
mAdapter.getLoadMoreModule().setLoadMoreView(new CustomLoadMoreView());
View footerView = getFooterView(0, new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ClickEventUtils.isFastClick()) {
ARouter.getInstance().build(RouterActivityPath.Main.PAGER_PAIRDEVICES)
.navigation();
}
}
});
mAdapter.addFooterView(footerView, 0);
binding.recyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
try {
if (ClickEventUtils.isFastClick()) {
if (mAdapter.getItem(position).getDevice() != null) {
CacheUtil.setChargePointId(mAdapter.getItem(position).getDevice().getChargePointId());
}
ARouter.getInstance().build(RouterActivityPath.Main.PAGER_CHARGING)
.withSerializable("DeviceListbean", mAdapter.getItem(position))
.navigation();
}
} catch (Exception e) {
LogUtils.e(e.toString());
}
}
});
mAdapter.addChildClickViewIds(R.id.imgright, R.id.imgschedules, R.id.imgbell);
mAdapter.setOnItemChildClickListener(new OnItemChildClickListener() {
@Override
public void onItemChildClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
try {
if (ClickEventUtils.isFastClick()) {
if (view.getId() == R.id.imgright) {
CacheUtil.setChargePointId(mAdapter.getItem(position).getDevice().getChargePointId());
ARouter.getInstance().build(RouterActivityPath.Main.PAGER_CHARGING)
.withSerializable("DeviceListbean", mAdapter.getItem(position))
.navigation();
} else if (view.getId() == R.id.imgschedules) {
ARouter.getInstance().build(RouterActivityPath.Schedules.PAGER_SCHEDULES)
.withString("chargePointId", mAdapter.getItem(position).getChargePointId())
.withString("idTag", mAdapter.getItem(position).getidTag())
.navigation();
} else if (view.getId() == R.id.imgbell) {
ARouter.getInstance().build(RouterActivityPath.Alarm.PAGER_ALARMLIST)
.withString("chargePointId", mAdapter.getItem(position).getChargePointId())
.withString("idTag", mAdapter.getItem(position).getidTag())
.navigation();
}
}
} catch (Exception e) {
LogUtils.e(e.toString());
}
}
});
initRefreshLayout();
initLoadMore();
}
private void initRefreshLayout() {
binding.swipeRefreshLayout.setColorSchemeColors(Color.rgb(47, 223, 189));
binding.swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refresh();
}
});
}
/**
* 初始化加载更多
*/
private void initLoadMore() {
mAdapter.getLoadMoreModule().setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
loadMore();
}
});
mAdapter.getLoadMoreModule().setAutoLoadMore(true);
//当自动加载开启,同时数据不满一屏时,是否继续执行自动加载更多(默认为true)
mAdapter.getLoadMoreModule().setEnableLoadMoreIfNotFullPage(false);
}
/**
* 刷新
*/
private void refresh() {
// 这里的作用是防止下拉刷新的时候还可以上拉加载
mAdapter.getLoadMoreModule().setEnableLoadMore(false);
page = 1;
getDeviceList();
}
/**
* 加载更多
*/
private void loadMore() {
getDeviceList();
}
@Override
public void onResume() {
super.onResume();
MqttManager.getInstance(getContext()).setMessageListener(this);
binding.swipeRefreshLayout.setRefreshing(true);
mAdapter.getData().clear();
page = 1;
}
@Override
public void onStart() {
super.onStart();
binding.swipeRefreshLayout.setRefreshing(true);
mAdapter.getData().clear();
page = 1;
getDeviceList();
}
@Override
public void onClick(View v) {
if (ClickEventUtils.isFastClick()) {
}
}
/**
* 获取设备列表
*/
private void getDeviceList() {
EasyHttp.get(this)
.api(new DeviceListApi()
.setPage(page)
.setSize(size))
.delay(1000)
.request(new OnHttpListener<HttpListData<DeviceListbean>>() {
@Override
public void onHttpSuccess(HttpListData<DeviceListbean> result) {
binding.swipeRefreshLayout.setRefreshing(false);
mAdapter.getLoadMoreModule().setEnableLoadMore(true);
if (result.getList() != null) {
if (page == 1) {
//如果是加载的第一页数据,用 setData()
mAdapter.setList(result.getList());
if (result.getList().isEmpty()) {
LogUtils.e("表示当前没有该账号绑定设备");
CacheUtil.clearBleMacAddress();
}
} else {
//不是第一页,则用add
mAdapter.addData(result.getList());
}
if (result.getList().size() < size) {
//如果不够一页,显示没有更多数据布局
mAdapter.getLoadMoreModule().loadMoreEnd();
} else {
mAdapter.getLoadMoreModule().loadMoreComplete();
}
page++;
if (!mAdapter.getData().isEmpty()) {
binding.textView.setVisibility(View.GONE);
subscribeMultiple();
}
}
}
@Override
public void onHttpFail(Throwable throwable) {
mAdapter.getData().clear();
binding.swipeRefreshLayout.setRefreshing(false);
mAdapter.getLoadMoreModule().setEnableLoadMore(true);
mAdapter.getLoadMoreModule().loadMoreFail();
}
});
}
/**
* 循环订阅
*/
private void subscribeMultiple() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// 在这里执行需要延迟的操作
if (!MqttManager.getInstance(getContext()).notConnected(true)) {
// 创建一个数组来存储设备主题
Set<String> bles = new HashSet<>();
int[] qos = new int[mAdapter.getData().size()];
// 遍历 mAdapter 数据,将设备主题添加到 topics 数组中
for (int i = 0; i < mAdapter.getData().size(); i++) {
DeviceListbean deviceListbean = mAdapter.getData().get(i);
if (deviceListbean != null) {
String chargePointId = deviceListbean.getChargePointId();
if (chargePointId != null) {
String topics = "smartiot-mqtt/topic/" + chargePointId; // 获取设备的主题名称
DeviceListbean.Device device = deviceListbean.getDevice();
if (device != null) {
String deviceBluetoothMac = device.getDeviceBluetoothMac();
if (deviceBluetoothMac != null) {
bles.add(deviceBluetoothMac);
} else {
LogUtils.e("设备的 Bluetooth MAC 地址为空: " + device);
}
} else {
LogUtils.e("设备为空: " + deviceListbean);
}
MqttManager.getInstance(getContext()).subscribe(topics, 0, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
MqttManager.getInstance(getContext()).addSubscription(asyncActionToken.getTopics()[0]);
triggerMessageReq(chargePointId);
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
LogUtils.e("订阅失败:" + asyncActionToken.getTopics()[0]);
}
});
} else {
LogUtils.e("ChargePointId 为空: " + deviceListbean);
}
} else {
LogUtils.e("mAdapter.getData().get(" + i + ") 返回 null");
}
}
CacheUtil.setBleListImei(bles);
}
}
}, 1000); // 1秒延迟,单位为毫秒
}
/**
* 触发消息
* 触发消息类型
* BootNotification-启动通知
* DiagnosticsStatusNotification-诊断通知
* FirmwareStatusNotification-固件升级状态通知
* Heartbeat-心跳通知MeterValues-实时数据
* StatusNotification-状态通知
*/
private void triggerMessageReq(String chargePointId) {
EasyHttp.post(this)
.api(new TriggerMessageReqApi()
.setChargePointId(chargePointId)
.setRequestedMessage("StatusNotification"))
.request(new OnHttpListener<HttpData<BaseBean>>() {
@Override
public void onHttpSuccess(HttpData<BaseBean> result) {
LogUtils.e(chargePointId + ":" + result.toString());
}
@Override
public void onHttpFail(Throwable throwable) {
LogUtils.e(chargePointId + ":" + throwable.getMessage());
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onMessageReceived(String topic, String message) {
LogUtils.mqtt("返回的订阅信息topic:" + topic);
LogUtils.mqtt("返回的订阅信息message:" + message);
try {
if (NetworkMonitor.isNetworkAvailable()) {
for (DeviceListbean deviceListbean : mAdapter.getData()) {
if (topic.equals("smartiot-mqtt/topic/" + deviceListbean.getChargePointId())) {
NetMessage netMessage = GsonFactory.getSingletonGson().fromJson(message, NetMessage.class);
switch (netMessage.getType()) {
case "StatusNotification": //状态通知
LogUtils.e("通知信息" + netMessage.getData());
NetStatusNotification notification = GsonFactory.getSingletonGson().fromJson(GsonFactory.getSingletonGson().toJson(netMessage.getData()), NetStatusNotification.class);
switch (notification.getStatus()) {
case "Available": //可用
deviceListbean.getDevice().getConnector().setConnectorStatus(ResUtils.getString(R.string.available));
break;
case "Preparing": //已插枪
deviceListbean.getDevice().getConnector().setConnectorStatus(ResUtils.getString(R.string.preparing));
break;
case "Charging": //充电中
deviceListbean.getDevice().getConnector().setConnectorStatus(ResUtils.getString(R.string.charging));
break;
case "Finishing": //充电完成
deviceListbean.getDevice().getConnector().setConnectorStatus(ResUtils.getString(R.string.finishing));
break;
case "Faulted":
deviceListbean.getDevice().getConnector().setConnectorStatus(ResUtils.getString(R.string.faulted));
break;
}
deviceListbean.getDevice().setErrorCode(notification.getErrorCode());
break;
case "MeterValues": //实时数据
LogUtils.e("实时数据" + netMessage.getData());
NetMeterValues netMeterValues = GsonFactory.getSingletonGson().fromJson(GsonFactory.getSingletonGson().toJson(netMessage.getData()), NetMeterValues.class);
NetUpdateMainUI(netMeterValues, deviceListbean);
break;
case "ChargeNetwork": //网络状态
LogUtils.e("网络状态" + netMessage.getData());
NetChargeNetwork netChargeNetwork = GsonFactory.getSingletonGson().fromJson(GsonFactory.getSingletonGson().toJson(netMessage.getData()), NetChargeNetwork.class);
if (netChargeNetwork.getStatus().equals(ResUtils.getString(R.string.connected))) {
LogUtils.e("采用网络优先模式");
MqttManager.getInstance(getContext()).setConnected(true);
} else if (netChargeNetwork.getStatus().equals(ResUtils.getString(R.string.disconnected))) {
LogUtils.e("桩断开平台了需要蓝牙连接");
MqttManager.getInstance(getContext()).setConnected(false);
}
break;
case "TransactionDuration": //充电时长
LogUtils.e("充电时长" + netMessage.getData());
NetTransactionDuration netTransactionDuration = GsonFactory.getSingletonGson().fromJson(GsonFactory.getSingletonGson().toJson(netMessage.getData()), NetTransactionDuration.class);
LogUtils.e("充电时间" + netTransactionDuration.getDuration());
int seconds = netTransactionDuration.getDuration();
int minutes = seconds / 60; // 计算分钟数
int remainingSeconds = seconds % 60; // 计算剩余秒数
// 计算小时数(如果需要)
int hours = minutes / 60; // 计算小时数
int remainingMinutes = minutes % 60; // 计算剩余分钟数
String timeString;
if (hours > 0) {
timeString = hours + ResUtils.getString(R.string.h) + remainingMinutes + ResUtils.getString(R.string.min);
} else {
timeString = minutes + ResUtils.getString(R.string.min);
}
deviceListbean.getDevice().setDuration(timeString);
break;
case "UpdateFirmware": //固件升级进度通知
LogUtils.e("固件升级进度通知" + netMessage.getData());
NetUpdateFirmware netUpdateFirmware = GsonFactory.getSingletonGson().fromJson(GsonFactory.getSingletonGson().toJson(netMessage.getData()), NetUpdateFirmware.class);
break;
case "FirmwareStatusNotification": //固件升级状态通知
LogUtils.e("固件升级状态通知" + netMessage.getData());
NetFirmwareStatusNotification netFirmwareStatusNotification = GsonFactory.getSingletonGson().fromJson(GsonFactory.getSingletonGson().toJson(netMessage.getData()), NetFirmwareStatusNotification.class);
break;
case "Heartbeat":
LogUtils.e("心跳" + netMessage.getData());
break;
}
}
}
mAdapter.notifyDataSetChanged();
}
} catch (Exception e) {
LogUtils.e(e.toString());
}
}
/**
* 网络数据更新UI
*
* @param
*/
private void NetUpdateMainUI(NetMeterValues message, DeviceListbean deviceListbean) {
if (message == null || message.getMeterValue() == null ||
message.getMeterValue().get(0).getSampledValue() == null ||
message.getMeterValue().get(0).getSampledValue().size() == 0) {
return;
}
List<BleMeterValues.SampledValue> listData = message.getMeterValue().get(0).getSampledValue();
String current = null;
String voltage = null;
for (BleMeterValues.SampledValue item : listData) {
String unit = item.getUnit();
String value = item.getValue();
switch (unit) {
case "Wh":
current = value;
// mBinding.chargingAmount.setText(value + " KWh");
break;
case "A":
current = value;
deviceListbean.getDevice().setChargingCurrent(value + ResUtils.getString(R.string.a));
break;
case "V":
voltage = value;
deviceListbean.getDevice().setChargingVoltage(value + ResUtils.getString(R.string.v));
break;
case "W":
deviceListbean.getDevice().setChargingPower(StringUtils.format2(Float.parseFloat(value) / 1000) + ResUtils.getString(R.string.kw));
break;
}
}
}
/**
* 蓝牙数据更新UI
*
* @param
*/
private void bleUpdateMainUI(BleMeterValues message, DeviceListbean deviceListbean) {
if (message == null || message.getMeterValue() == null ||
message.getMeterValue().get(0).getSampledValue() == null ||
message.getMeterValue().get(0).getSampledValue().size() == 0) {
return;
}
List<BleMeterValues.SampledValue> listData = message.getMeterValue().get(0).getSampledValue();
String current = null;
String voltage = null;
for (BleMeterValues.SampledValue item : listData) {
String unit = item.getUnit();
String value = item.getValue();
switch (unit) {
case "Wh":
current = value;
// mBinding.chargingAmount.setText(value + " KWh");
break;
case "A":
current = value;
deviceListbean.getDevice().setChargingCurrent(value + ResUtils.getString(R.string.a));
break;
case "V":
voltage = value;
deviceListbean.getDevice().setChargingVoltage(value + ResUtils.getString(R.string.v));
break;
case "W":
deviceListbean.getDevice().setChargingPower(StringUtils.format2(Float.parseFloat(value) / 1000) + ResUtils.getString(R.string.kw));
break;
}
}
}
@Override
public void onNetworkStateChanged(String networkType) {
LogUtils.e("当前网络状态:" + networkType);
}
private View getFooterView(int type, View.OnClickListener listener) {
View view = getLayoutInflater().inflate(R.layout.home_footer, binding.recyclerView, false);
view.setOnClickListener(listener);
return view;
}
}

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<LinearLayout
android:id="@+id/topll"
android:layout_width="match_parent"
android:layout_height="@dimen/topbar_height"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="@string/home"
android:textColor="@color/white"
android:textSize="@dimen/topbar_title_textsize" />
</LinearLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topll"
app:layout_constraintVertical_bias="0.05"
app:layout_constraintWidth_percent="0.9">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/no_chargers_yet"
android:textColor="@color/white"
android:textSize="@dimen/textsize30"
tools:text="@string/no_chargers_yet" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal">
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/add" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="15dp"
android:text="@string/add_charger"
android:textColor="@color/grey"
android:textSize="@dimen/textsize22" />
</LinearLayout>

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="149dp"
android:layout_marginBottom="20dp"
android:background="@drawable/button_grey_5">
<LinearLayout
android:id="@+id/linearLayout4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0">
<ImageView
android:id="@+id/img"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="15dp"
android:src="@drawable/switch_on"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/name"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.1" />
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:textColor="@color/white"
android:textSize="@dimen/textsize20"
tools:text="@string/home" />
<ImageView
android:id="@+id/imgbell"
android:layout_width="16dp"
android:layout_height="18dp"
android:src="@drawable/bell"
android:visibility="gone" />
<ImageView
android:id="@+id/imgschedules"
android:layout_width="23dp"
android:layout_height="24dp"
android:layout_marginStart="19dp"
android:src="@drawable/schedules" />
<ImageView
android:id="@+id/imgright"
android:layout_width="29dp"
android:layout_height="29dp"
android:layout_marginStart="17dp"
android:layout_marginEnd="18dp"
android:src="@drawable/list_right" />
</LinearLayout>
<TextView
android:id="@+id/state"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:textColor="@color/color_64696E"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout4"
app:layout_constraintVertical_bias="0.2" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/state"
app:layout_constraintVertical_bias="0.5">
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:textColor="@color/white"
android:textSize="@dimen/textsize18"
tools:text="@string/_11_min_24_sec" />
<TextView
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginStart="22dp"
android:background="#D7D7D7" />
<TextView
android:id="@+id/power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:textColor="@color/white"
android:textSize="@dimen/textsize18"
tools:text="@string/_60_kwh" />
<TextView
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginStart="18dp"
android:background="#D7D7D7" />
<TextView
android:id="@+id/Current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="22dp"
android:textColor="@color/white"
android:textSize="@dimen/textsize18"
tools:text="@string/_15a" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,17 @@
package com.snc.home;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

@ -0,0 +1 @@
/build

@ -0,0 +1,114 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
android {
namespace 'com.snc.base'
compileSdk rootProject.ext.android.compileSdk
defaultConfig {
minSdk rootProject.ext.android.minSdk
targetSdk rootProject.ext.android.targetSdk
multiDexEnabled rootProject.ext.android.multiDexEnabled
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
ndk {
// SO库架构
abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures {
//2 ViewBinding & DataBinding
dataBinding = true
viewBinding = true
buildConfig = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
//
packagingOptions {
exclude 'META-INF/NOTICE.md'
exclude 'META-INF/LICENSE.md'
}
}
dependencies {
api 'androidx.core:core-ktx:1.13.1'
api 'androidx.appcompat:appcompat:1.6.1'
api 'com.google.android.material:material:1.12.0'
api 'androidx.activity:activity-ktx:1.9.0'
api 'androidx.constraintlayout:constraintlayout:2.1.4'
api 'androidx.navigation:navigation-fragment-ktx:2.7.7'
api 'androidx.navigation:navigation-ui-ktx:2.7.7'
//
//
api 'com.alibaba:arouter-api:1.5.2'
//MMKV
api 'com.tencent:mmkv:1.3.5'
//
api 'com.github.hackware1993:MagicIndicator:1.7.0'
//
api 'com.github.getActivity:XXPermissions:18.63'
//MQTTX
api 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
api 'org.bouncycastle:bcpkix-jdk15on:1.67'
api 'androidx.legacy:legacy-support-v4:1.0.0'
api project(':org.eclipse.paho.android.service')
// PictureSelector ()
api 'io.github.lucksiege:pictureselector:v3.11.2'
// ()
api 'io.github.lucksiege:compress:v3.11.2'
// ()
api 'io.github.lucksiege:ucrop:v3.11.2'
//
api 'com.airbnb.android:lottie:6.4.0'
//
api 'com.github.bumptech.glide:glide:4.16.0'
//
// https://github.com/getActivity/EasyHttp
api 'com.github.getActivity:EasyHttp:12.8'
// OkHttp https://github.com/square/okhttp
// noinspection GradleDependency
api 'com.squareup.okhttp3:okhttp:3.12.13'
// Gson https://github.com/getActivity/GsonFactory
api 'com.github.getActivity:GsonFactory:9.5'
// Json https://github.com/google/gson
api 'com.google.code.gson:gson:2.10.1'
//
api 'com.github.JessYanCoding:AndroidAutoSize:v1.2.1'
api 'com.android.support:multidex:1.0.3'
//
api 'io.github.cymchad:BaseRecyclerViewAdapterHelper:3.0.14'
// Bugly https://bugly.qq.com/docs/user-guide/instruction-manual-android/?v=20190418140644
api 'com.tencent.bugly:crashreport:4.1.9.3'
//Google LiveData和ViewModel组件
api "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.1"
// LiveData
api "androidx.lifecycle:lifecycle-livedata-ktx:2.8.1"
api 'com.kunminx.arch:unpeek-livedata:7.8.0'
//
implementation 'com.sun.mail:android-mail:1.6.7'
implementation 'com.sun.mail:android-activation:1.6.7'
}

@ -0,0 +1,235 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#保留我们使用的四大组件,自定义的Application等等这些类不被混淆
# 因为这些子类都有可能被外部调用
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
# 保留support下的所有类及其内部类
-keep class android.support.** {*;}
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
# 保留R下面的资源
-keep class **.R$* {*;}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保留在Activity中的方法参数是view的方法,
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
# 保留枚举类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 保留我们自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**
-dontwarn androidx.**
#me.jessyan:autosize:1.1.2
-keep class me.jessyan.autosize.** { *; }
-keep interface me.jessyan.autosize.** { *; }
#com.hjq:xxpermissions:9.6
-dontwarn com.hjq.permissions.**
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties { *; }
# If you DO use SQLCipher:
-keep class org.greenrobot.greendao.database.SqlCipherEncryptedHelper { *; }
# If you do NOT use SQLCipher:
-dontwarn net.sqlcipher.database.**
# If you do NOT use RxJava:
-dontwarn rx.**
-dontwarn com.jeremyliao.liveeventbus.**
-keep class com.jeremyliao.liveeventbus.** { *; }
-keep class androidx.lifecycle.** { *; }
-keep class androidx.arch.core.** { *; }
-dontwarn com.kingja.loadsir.**
-keep class com.kingja.loadsir.** {*;}
-keep class com.tencent.** {*;}
-keep class com.tencent.mmkv.** {*;}
-keep class com.luck.picture.lib.** { *; }
# use Camerax
-keep class com.luck.lib.camerax.** { *; }
# use uCrop
-dontwarn com.yalantis.ucrop**
-keep class com.yalantis.ucrop** { *; }
-keep interface com.yalantis.ucrop** { *; }
# Fastjson 混淆规则
-keep public class com.alibaba.fastjson.JSON {
public static ** toJSONString(**);
public static ** parseObject(**);
public static ** parseArray(**);
public static ** parse(**);
}
-keep public class com.alibaba.fastjson.** {
public <init>(org.json.JSONObject);
}
-keep public class * implements com.alibaba.fastjson.serializer.ObjectSerializer {
public <init>();
}
-keep public class * implements com.alibaba.fastjson.parser.deserializer.ObjectDeserializer {
public <init>();
}
-keep class com.alibaba.fastjson.parser.ParserConfig {
public <init>();
public static void putDeserializer(java.lang.Class, com.alibaba.fastjson.parser.deserializer.ObjectDeserializer);
}
-keep class com.alibaba.fastjson.serializer.SerializeConfig {
public <init>();
public static void putSerializer(java.lang.Class, com.alibaba.fastjson.serializer.ObjectSerializer);
}
-keep class com.alibaba.fastjson.util.TypeUtils {
public static void register(java.lang.Class, java.lang.Class);
}
# 如果使用了AutoType的功能,需要保留下面的类不被混淆
-keepattributes Signature
-keepattributes *Annotation*
-keepclassmembers class * {
@com.alibaba.fastjson.annotation.JSONField <fields>;
@com.alibaba.fastjson.annotation.JSONType <fields>;
}
# 如果使用了enum类型的序列化,需要保留enum的名字
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 如果使用了ASM的ClassGenerator,需要保留下面的类不被混淆
-dontnote com.alibaba.fastjson.asm.**
-keep class com.alibaba.fastjson.asm.** { *; }
##Glide
-dontwarn com.bumptech.glide.**
-keep class com.bumptech.glide.**{*;}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.hjq.permissions.** {*;}
#Bugly
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# OkHttp3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
# EasyHttp
-keep class com.hjq.http.** {*;}
# 必须要加上此规则,否则会导致泛型解析失败
-keep public class * implements com.hjq.http.listener.OnHttpListener {
*;
}
# 不混淆这个包下的类
-keep class com.snc.base.http.** {
<fields>;
}

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<meta-data
android:name="design_width_in_dp"
android:value="375" />
<meta-data
android:name="design_height_in_dp"
android:value="812" />
</application>
</manifest>

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,80 @@
package com.snc.base.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.chad.library.adapter.base.loadmore.BaseLoadMoreView;
import com.chad.library.adapter.base.loadmore.LoadMoreStatus;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.snc.base.R;
import org.jetbrains.annotations.NotNull;
public final class CustomLoadMoreView extends BaseLoadMoreView {
@NotNull
@Override
public View getRootView(@NotNull ViewGroup parent) {
return LayoutInflater.from(parent.getContext()).inflate(R.layout.view_load_more, parent, false);
}
@NotNull
@Override
public View getLoadingView(@NotNull BaseViewHolder holder) {
return holder.findView(R.id.load_more_loading_view);
}
@NotNull
@Override
public View getLoadComplete(@NotNull BaseViewHolder holder) {
return holder.findView(R.id.load_more_load_complete_view);
}
@NotNull
@Override
public View getLoadEndView(@NotNull BaseViewHolder holder) {
return holder.findView(R.id.load_more_load_end_view);
}
@NotNull
@Override
public View getLoadFailView(@NotNull BaseViewHolder holder) {
return holder.findView(R.id.load_more_load_fail_view);
}
@Override
public void convert(@NonNull BaseViewHolder holder, int position, @NonNull LoadMoreStatus loadMoreStatus) {
super.convert(holder, position, loadMoreStatus);
switch (loadMoreStatus){
case Complete:
getLoadingView(holder).setVisibility(View.GONE);
getLoadComplete(holder).setVisibility(View.VISIBLE);
getLoadFailView(holder).setVisibility(View.GONE);
getLoadEndView(holder).setVisibility(View.GONE);
break;
case Loading:
getLoadingView(holder).setVisibility(View.VISIBLE);
getLoadComplete(holder).setVisibility(View.GONE);
getLoadFailView(holder).setVisibility(View.GONE);
getLoadEndView(holder).setVisibility(View.GONE);
break;
case Fail:
getLoadingView(holder).setVisibility(View.GONE);
getLoadComplete(holder).setVisibility(View.GONE);
getLoadFailView(holder).setVisibility(View.VISIBLE);
getLoadEndView(holder).setVisibility(View.GONE);
break;
case End:
getLoadingView(holder).setVisibility(View.GONE);
getLoadComplete(holder).setVisibility(View.GONE);
getLoadFailView(holder).setVisibility(View.GONE);
getLoadEndView(holder).setVisibility(View.GONE);
break;
}
}
}

@ -0,0 +1,32 @@
package com.snc.base.adapter.animator;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import com.chad.library.adapter.base.animation.BaseAnimation;
import org.jetbrains.annotations.NotNull;
/**
* 自定义动画1
*/
public class CustomAnimation1 implements BaseAnimation {
@NotNull
@Override
public Animator[] animators(@NotNull View view) {
Animator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1.3f, 1);
Animator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1.3f, 1);
Animator alpha = ObjectAnimator.ofFloat(view, "alpha", 0, 1f);
scaleY.setDuration(350);
scaleX.setDuration(350);
alpha.setDuration(350);
scaleY.setInterpolator(new DecelerateInterpolator());
scaleX.setInterpolator(new DecelerateInterpolator());
return new Animator[]{scaleY, scaleX, alpha};
}
}

@ -0,0 +1,40 @@
package com.snc.base.adapter.animator;
import static java.lang.Math.PI;
import static java.lang.Math.pow;
import static java.lang.Math.sin;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
import android.view.animation.Interpolator;
import com.chad.library.adapter.base.animation.BaseAnimation;
import org.jetbrains.annotations.NotNull;
/**
* 自定义动画2
*/
public class CustomAnimation2 implements BaseAnimation {
@NotNull
@Override
public Animator[] animators(@NotNull View view) {
Animator translationX =
ObjectAnimator.ofFloat(view, "translationX", -view.getRootView().getWidth(), 0f);
translationX.setDuration(800);
translationX.setInterpolator(new MyInterpolator2());
return new Animator[]{translationX};
}
class MyInterpolator2 implements Interpolator {
@Override
public float getInterpolation(float input) {
float factor = 0.7f;
return (float) (pow(2.0, -10.0 * input) * sin((input - factor / 4) * (2 * PI) / factor) + 1);
}
}
}

@ -0,0 +1,27 @@
package com.snc.base.adapter.animator;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import com.chad.library.adapter.base.animation.BaseAnimation;
import org.jetbrains.annotations.NotNull;
public class CustomAnimation3 implements BaseAnimation {
@NotNull
@Override
public Animator[] animators(@NotNull View view) {
Animator alpha = ObjectAnimator.ofFloat(view, "alpha", 0, 1f);
alpha.setDuration(450);
Animator translationY =
ObjectAnimator.ofFloat(view, "translationY", view.getRootView().getHeight(), 0f);
translationY.setDuration(450);
translationY.setInterpolator(new DecelerateInterpolator(1.2f));
return new Animator[]{alpha, translationY};
}
}

@ -0,0 +1,207 @@
package com.snc.base.base;
import android.app.Activity;
import androidx.fragment.app.Fragment;
import com.snc.base.utils.LogUtils;
import java.util.Stack;
public class AppManager {
private static Stack<Activity> activityStack;
private static Stack<Fragment> fragmentStack;
private static AppManager instance;
private AppManager() {
}
/**
* 单例模式
*
* @return AppManager
*/
public static AppManager getAppManager() {
if (instance == null) {
instance = new AppManager();
}
return instance;
}
public static Stack<Activity> getActivityStack() {
return activityStack;
}
public static Stack<Fragment> getFragmentStack() {
return fragmentStack;
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity) {
if (activityStack == null) {
activityStack = new Stack<Activity>();
}
activityStack.add(activity);
}
/**
* 移除指定的Activity
*/
public void removeActivity(Activity activity) {
if (activity != null) {
activityStack.remove(activity);
}
}
/**
* 是否有activity
*/
public boolean isActivity() {
if (activityStack != null) {
return !activityStack.isEmpty();
}
return false;
}
/**
* 获取当前Activity堆栈中最后一个压入的
*/
public Activity currentActivity() {
Activity activity = activityStack.lastElement();
return activity;
}
/**
* 结束当前Activity堆栈中最后一个压入的
*/
public void finishActivity() {
Activity activity = activityStack.lastElement();
finishActivity(activity);
}
/**
* 结束指定的Activity
*/
public void finishActivity(Activity activity) {
if (activity != null) {
LogUtils.e(activity.getClass().getName());
if (!activity.isFinishing()) {
activity.finish();
}
}
}
/**
* 结束指定类名的Activity
*/
public void finishActivity(Class<?> cls) {
for (Activity activity : activityStack) {
if (activity.getClass().equals(cls)) {
finishActivity(activity);
break;
}
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (int i = 0, size = activityStack.size(); i < size; i++) {
if (null != activityStack.get(i)) {
finishActivity(activityStack.get(i));
}
}
activityStack.clear();
}
/**
* 保留最后一个Activity
*/
public void endActivity() {
for (int i = 1, size = activityStack.size(); i < size; i++) {
if (null != activityStack.get(i)) {
finishActivity(activityStack.get(i));
}
}
activityStack.clear();
}
/**
* 获取指定的Activity
*
* @author kymjs
*/
public Activity getActivity(Class<?> cls) {
if (activityStack != null)
for (Activity activity : activityStack) {
if (activity.getClass().equals(cls)) {
return activity;
}
}
return null;
}
/**
* 添加Fragment到堆栈
*/
public void addFragment(Fragment fragment) {
if (fragmentStack == null) {
fragmentStack = new Stack<Fragment>();
}
fragmentStack.add(fragment);
}
/**
* 移除指定的Fragment
*/
public void removeFragment(Fragment fragment) {
if (fragment != null) {
fragmentStack.remove(fragment);
}
}
/**
* 是否有Fragment
*/
public boolean isFragment() {
if (fragmentStack != null) {
return !fragmentStack.isEmpty();
}
return false;
}
/**
* 获取当前Activity堆栈中最后一个压入的
*/
public Fragment currentFragment() {
if (fragmentStack != null) {
Fragment fragment = fragmentStack.lastElement();
return fragment;
}
return null;
}
/**
* 退出应用程序
*/
public void AppExit() {
try {
finishAllActivity();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Exception e) {
activityStack.clear();
e.printStackTrace();
}
}
}

@ -0,0 +1,473 @@
package com.snc.base.base;
import static com.snc.base.ble.constant.BleConstant.WRITE;
import static com.snc.base.utils.AppUtils.getContext;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import com.alibaba.android.arouter.launcher.ARouter;
import com.snc.base.R;
import com.snc.base.ble.BleDeviceCore;
import com.snc.base.ble.BluetoothServiceManager;
import com.snc.base.ble.callback.BleConnectMsgCallback;
import com.snc.base.ble.callback.BleMtuMsgCallback;
import com.snc.base.ble.callback.BleNotifyMsgCallback;
import com.snc.base.ble.callback.BleWriteMsgCallback;
import com.snc.base.ble.callback.CharacteristicChangedCallback;
import com.snc.base.ble.constant.BleConstant;
import com.snc.base.ble.model.BleDevice;
import com.snc.base.constant.Constant;
import com.snc.base.dialog.TDialog;
import com.snc.base.dialog.base.BindViewHolder;
import com.snc.base.dialog.listener.OnBindViewListener;
import com.snc.base.dialog.listener.OnViewClickListener;
import com.snc.base.http.bean.DeviceListbean;
import com.snc.base.mqtt.MqttManager;
import com.snc.base.mqtt.MqttMessageListener;
import com.snc.base.network.NetworkMonitor;
import com.snc.base.utils.BluetoothUtils;
import com.snc.base.utils.ClickEventUtils;
import com.snc.base.utils.LogUtils;
import java.util.List;
import java.util.UUID;
import me.jessyan.autosize.AutoSize;
public abstract class BaseActivity<T extends ViewDataBinding> extends AppCompatActivity implements
View.OnClickListener, MqttMessageListener, NetworkMonitor.NetworkStateListener {
protected T mBinding;
// protected BleDeviceCore bleCore;
// protected BluetoothServiceManager serviceManager = BluetoothServiceManager.getInstance();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, getContentLayoutId());
// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // 禁用横屏
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//屏幕保持常亮
ARouter.getInstance().inject(this);//参数
// bleCore = BleDeviceCore.Companion.getInstance(this);
initListener();
initData();
}
@Override
protected void onResume() {
super.onResume();
NetworkMonitor.setNetworkStateListener(this);
//确保每次Mqtt返回的信息在当前页面
MqttManager.getInstance(this).setMessageListener(this);
// 确保重新绑定回调
// if (bleCore != null) {
// bleCore.setCharacteristicChangedCallback(this);
// }
}
/**
* 返回子类的 layoutId
*
* @return
*/
protected abstract int getContentLayoutId();
protected abstract void initListener();
/**
* 初始化数据
*/
protected abstract void initData();
@Override
protected void onDestroy() {
super.onDestroy();
}
/**
* 设置全屏显示
*
* @param hasFocus
*/
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && Build.VERSION.SDK_INT >= 19) {
View decorView = getWindow().getDecorView();
// decorView.setSystemUiVisibility(
// View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
// | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
// | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
// | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
// View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (isShouldHideInput(v, ev)) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
v.clearFocus();
onWindowFocusChanged(true);
}
}
return super.dispatchTouchEvent(ev);
}
// 必不可少,否则所有的组件都不会有TouchEvent了
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
/**
* 点击输入框外 隐藏软键盘
*
* @param v
* @param event
* @return
*/
public boolean isShouldHideInput(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] leftTop = {0, 0};
//获取输入框当前的location位置
v.getLocationInWindow(leftTop);
int left = leftTop[0];
int top = leftTop[1];
int bottom = top + v.getHeight();
int right = left + v.getWidth();
if (event.getX() > left && event.getX() < right && event.getY() > top && event.getY() < bottom) {
// 点击的是输入框区域,保留点击EditText的事件
return false;
} else {
return true;
}
}
return false;
}
@Override
public boolean moveTaskToBack(boolean nonRoot) {
return super.moveTaskToBack(true);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
AutoSize.autoConvertDensityOfGlobal(this);
}
@Override
public Resources getResources() {
// AutoSizeCompat.autoConvertDensity((super.getResources()), 375, true);//如果有自定义需求就用这个方法
// return super.getResources();
Resources res = super.getResources();
Configuration config = new Configuration();
config.setToDefaults();
res.updateConfiguration(config, res.getDisplayMetrics());
return res;
}
public void TipsSingleDialog(String string) {
new TDialog.Builder(getSupportFragmentManager())
.setLayoutRes(R.layout.dialog_tip)
.setScreenWidthAspect(this, 0.8f) //设置弹窗宽度(参数aspect为屏幕宽度比例 0 - 1f)
.setGravity(Gravity.CENTER) //设置弹窗展示位置
.setDimAmount(0.3f) //设置弹窗背景透明度(0-1f)
.setCancelableOutside(false) //弹窗在界面外是否可以点击取消
.addOnClickListener(R.id.tip_ok)
.setOnBindViewListener(new OnBindViewListener() { //通过BindViewHolder拿到控件对象,进行修改
@Override
public void bindView(BindViewHolder bindViewHolder) {
bindViewHolder.setText(R.id.tip_msg, string);
}
}).setOnViewClickListener(new OnViewClickListener() {
@Override
public void onViewClick(BindViewHolder viewHolder, View view, TDialog tDialog) {
int id = view.getId();
if (id == R.id.tip_ok) {
tDialog.dismiss();
}
}
}).create().show();
}
TDialog dialog;
/**
* 生成加载框
*/
public void dialogLoading() {
dialog = new TDialog.Builder(getSupportFragmentManager())
.setLayoutRes(R.layout.dialog_loading)
.setScreenWidthAspect(getContext(), 0.8f) //设置弹窗宽度(参数aspect为屏幕宽度比例 0 - 1f)
.setScreenHeightAspect(getContext(), 0.2f) //设置弹窗宽度(参数aspect为屏幕宽度比例 0 - 1f)
.setGravity(Gravity.CENTER) //设置弹窗展示位置
.setDimAmount(0.8f) //设置弹窗背景透明度(0-1f)
.setCancelableOutside(false) //弹窗在界面外是否可以点击取消
.create().show();
// new Handler().postDelayed(() -> {
// if (dialog != null) {
// dialog.dismiss();
// }
// }, Millis * 1000);
}
/**
* 显示加载框
*/
public void showLoading() {
try {
dialogLoading();
} catch (Exception e) {
LogUtils.e(e.toString());
}
}
/**
* 关闭加载框
*/
public void hideLoading() {
try {
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
} catch (Exception e) {
LogUtils.e(e.toString());
}
}
/**
* 提示文字
*
* @param msg 文字
*/
protected void showMsg(CharSequence msg) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
/**
* 当前那个桩自动连接蓝牙
*/
// protected void AutoBle(DeviceListbean deviceListbean) {
// LogUtils.e("自动蓝牙连接");
// if (bleCore.isConnected()) {
// bleCore.disconnect();
// }
// BluetoothDevice device = BluetoothUtils.getBluetoothDevice(getContext(), deviceListbean.getDevice().getDeviceBluetoothMac());
// if (device != null) {
// new Handler().postDelayed(new Runnable() {
// @Override
// public void run() {
// bleCore.connect2(device, new BleConnectMsgCallback<BleDevice>() {
// @Override
// public void onConnectionSuccess(@Nullable BluetoothGatt gatt) {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// LogUtils.e("You are connected to Bluetooth " + deviceListbean.getDevice().getDeviceName());
// showMsg("You are connected to Bluetooth " + deviceListbean.getDevice().getDeviceName());
// }
// });
// }
//
// @Override
// public void onConnectionFailure(@NonNull String failedMsg) {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// LogUtils.e(failedMsg);
// showMsg(failedMsg);
// }
// });
// }
// });
// }
// }, 1000);
// } else {
// LogUtils.e("蓝牙没有连接");
// }
// }
/**
* 蓝牙连接
*
* @param bleDevice
*/
// protected void bleConnet(BleDevice bleDevice) {
// if (bleCore.isConnected()) {
// bleCore.disconnect();
// }
// bleCore.connect2(bleDevice.getDevice(), new BleConnectMsgCallback<BleDevice>() {
// @Override
// public void onConnectionSuccess(@Nullable BluetoothGatt gatt) {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// LogUtils.e("You are connected to Bluetooth " + bleDevice.getRealName());
// showMsg("You are connected to Bluetooth " + bleDevice.getRealName());
// }
// });
// }
//
// @Override
// public void onConnectionFailure(@NonNull String failedMsg) {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// LogUtils.e(failedMsg);
// showMsg(failedMsg);
// }
// });
// }
// });
// }
/**
* 设置MTU
*/
// protected void setMTU() {
// bleCore.requestMtu(512, new BleMtuMsgCallback<BleDevice>() {
// @Override
// public void onMtuSuccess(@NonNull BluetoothGatt gatt, int mtu, int status) {
// LogUtils.d("onMtuSuccess-------------" + "mtu---------" + mtu);
// belSetALLNotify(serviceManager.getServiceList().get(2).getCharacteristics());
// }
//
// @Override
// public void onMtuFailed(@NonNull BluetoothGatt gatt, int mtu, int status) {
// LogUtils.e("onMtuFailed-------------" + "status---------" + status);
// }
// });
// }
/**
* 发送蓝牙信息
*/
// protected void sendBluetoothMsg(Integer pos, String msg, List<BluetoothGattCharacteristic> characteristicList) {
// try {
// switch (pos) {
// case 0: // Todo FF01 用于原来的业务,包括开始充电、停止充电、实时数据
// break;
// case 1: // Todo FF02 用于Wifi配网
// break;
// case 2: // Todo FF03 用于设备激活与绑定
// break;
// }
//
// LogUtils.ble("蓝牙发送信息----" + pos + "------" + msg);
// LogUtils.ble("蓝牙发送信息-uuid-pos----" + "----1--" + characteristicList.get(pos).getUuid());
//
// if (characteristicList.get(pos) != null) {
// BluetoothGattCharacteristic characteristic = characteristicList.get(pos);
// // 发送数据
// bleWriteData(characteristic, msg, WRITE);
// } else {
// showMsg("Bluetooth sending failed");
// }
// } catch (NumberFormatException e) {
// e.printStackTrace();
// }
// }
/**
* 蓝牙真正数据发送
*/
// protected void bleWriteData(BluetoothGattCharacteristic characteristic, String msg, String writeType) {
// if (bleCore != null) {
// new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
// @Override
// public void run() {
// bleCore.writeCharacteristic(characteristic, msg, writeType, new BleWriteMsgCallback<BleDevice>() {
// @Override
// public void onWriteSuccess(BluetoothGattCharacteristic characteristic) {
// LogUtils.e("发送成功");
// }
//
// @Override
// public void onWriteFailed(BluetoothGattCharacteristic characteristic) {
// LogUtils.e("发送失败");
// }
// });
// }
// }, 2000);
//
// }
// }
/**
* 打开蓝牙接受通知
*/
// protected void bleSetNotify(BluetoothGattCharacteristic characteristic, String notifyType) {
// if (bleCore != null) {
// bleCore.notifyEnable(characteristic, characteristic.getDescriptors().get(0).getUuid(), notifyType, new BleNotifyMsgCallback<BleDevice>() {
// @Override
// public void onNotifySuccess(BluetoothGattCharacteristic characteristic) {
// LogUtils.e("打开通知成功" + characteristic.getUuid());
// }
//
// @Override
// public void onNotifyFailed(BleDevice device, String failedMsg) {
// LogUtils.e("打开通知失败" + characteristic.getUuid());
// }
// });
// }
// }
/**
* 打开蓝牙的通知
*
* @param list
*/
// protected void belSetALLNotify(List<BluetoothGattCharacteristic> list) {
// for (BluetoothGattCharacteristic characteristic : list) {
// if (characteristic.getUuid().equals(UUID.fromString(Constant.UUID_01))) {
// bleSetNotify(characteristic, BleConstant.NOTIFY);
// } else if (characteristic.getUuid().equals(UUID.fromString(Constant.UUID_02))) {
// bleSetNotify(characteristic, BleConstant.NOTIFY);
// } else if (characteristic.getUuid().equals(UUID.fromString(Constant.UUID_03))) {
// bleSetNotify(characteristic, BleConstant.NOTIFY);
// }
// }
// }
}

@ -0,0 +1,81 @@
package com.snc.base.base;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.multidex.MultiDexApplication;
import com.snc.base.config.ModuleLifecycleConfig;
import com.snc.base.utils.AppUtils;
public class BaseApplication extends MultiDexApplication {
private static Application sInstance;
@Override
public void onCreate() {
super.onCreate();
setApplication(this);
//初始化组件(靠前)
ModuleLifecycleConfig.getInstance().initModuleAhead(this);
//....
//初始化组件(靠后)
ModuleLifecycleConfig.getInstance().initModuleLow(this);
}
/**
* 当主工程没有继承BaseApplication时可以使用setApplication方法初始化BaseApplication
*
* @param application
*/
public static synchronized void setApplication(@NonNull Application application) {
sInstance = application;
//初始化工具类
AppUtils.init(application);
//注册监听每个activity的生命周期,便于堆栈式管理
application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) {
AppManager.getAppManager().addActivity(activity);
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
AppManager.getAppManager().removeActivity(activity);
}
});
}
/**
* 获得当前app运行的Application
*/
public static Application getInstance() {
if (sInstance == null) {
throw new NullPointerException("please inherit BaseApplication or call setApplication.");
}
return sInstance;
}
}

@ -0,0 +1,106 @@
package com.snc.base.base;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
import androidx.viewbinding.ViewBinding;
import com.snc.base.network.NetworkMonitor;
import com.snc.base.utils.AppUtils;
import com.snc.base.utils.LogUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class BaseFragment<T extends ViewBinding> extends Fragment implements View.OnClickListener, NetworkMonitor.NetworkStateListener {
protected T binding;
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Type superclass = getClass().getGenericSuperclass();
Class<?> aClass = (Class<?>) ((ParameterizedType) superclass).getActualTypeArguments()[0];
try {
Method method = aClass.getDeclaredMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
binding = (T) method.invoke(null, getLayoutInflater(), container, false);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
if (binding == null) {
LogUtils.e("ViewBinding is null");
} else {
LogUtils.e("ViewBinding is initialized");
}
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
NetworkMonitor.setNetworkStateListener(this);
initListener();
initData();
}
protected abstract void initListener();
/**
* 初始化数据
*/
protected abstract void initData();
/**
* 显示加载框
*/
public void showLoading() {
if (getActivity() instanceof BaseActivity) {
((BaseActivity<?>) getActivity()).showLoading();
}
}
@Override
public void onPause() {
super.onPause();
try {
hideLoading();
} catch (Exception e) {
LogUtils.e(e.toString());
}
}
/**
* 关闭加载框
*/
protected void hideLoading() {
if (getActivity() instanceof BaseActivity) {
((BaseActivity<?>) getActivity()).hideLoading();
}
}
// 判断当前 Fragment 是否可见
private boolean isFragmentVisible() {
return isVisible();
}
/**
* 提示文字
*
* @param msg 文字
*/
protected void showMsg(CharSequence msg) {
Toast.makeText(AppUtils.getContext(), msg, Toast.LENGTH_LONG).show();
}
}

@ -0,0 +1,163 @@
package com.snc.base.base;
import android.app.Application;
import androidx.annotation.NonNull;
import com.alibaba.android.arouter.launcher.ARouter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonToken;
import com.hjq.gson.factory.GsonFactory;
import com.hjq.gson.factory.ParseExceptionCallback;
import com.hjq.http.EasyConfig;
import com.hjq.http.config.IRequestInterceptor;
import com.hjq.http.config.IRequestServer;
import com.hjq.http.model.HttpHeaders;
import com.hjq.http.model.HttpParams;
import com.hjq.http.request.HttpRequest;
import com.snc.base.BuildConfig;
import com.snc.base.http.model.RequestHandler;
import com.snc.base.http.server.ReleaseServer;
import com.snc.base.http.server.TestServer;
import com.snc.base.network.NetworkMonitor;
import com.snc.base.utils.CacheUtil;
import com.snc.base.utils.LogUtils;
import com.snc.base.utils.MVUtils;
import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.mmkv.MMKV;
import okhttp3.OkHttpClient;
public class BaseModuleInit implements IModuleInit {
private NetworkMonitor networkMonitor;
@Override
public boolean onInitAhead(Application application) {
ininARouter(application);
/**
*配置LifecycleObserver如Activity接收消息的模式默认值true
*
* true整个生命周期从onCreate到onDestroy都可以实时收到消息
* false激活状态Started可以实时收到消息非激活状态Stoped无法实时收到消息需等到Activity重新变成激活状态方可收到消息
* enableLogger
* 配置是否打印日志默认打印日志
*/
// LiveEventBus.config().autoClear(true).enableLogger(true).lifecycleObserverAlwaysActive(false);
LogUtils.e("基础层初始化 -- onInitAhead");
return false;
}
@Override
public boolean onInitLow(Application application) {
initMMKV(application);
initEasyHttp(application);
initNetworkMonitor(application);
initBugly(application);
LogUtils.e("基础层初始化 -- onInitLow");
return false;
}
private void ininARouter(Application application) {
//初始化阿里路由框架
if (BuildConfig.DEBUG) {
LogUtils.setIsPrintLog(true);
LogUtils.setSaveLogToFile(true);
LogUtils.initialize(application);
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
} else {
LogUtils.setIsPrintLog(false);
LogUtils.setSaveLogToFile(true);
LogUtils.initialize(application);
}
ARouter.init(application); // 尽可能早,推荐在Application中初始化
}
private void initMMKV(Application application) {
//MMKV初始化
String initialize = MMKV.initialize(application);
LogUtils.i("MMKV INIT " + initialize);
//工具类初始化
MVUtils.getInstance();
}
private void initNetworkMonitor(Application application) {
networkMonitor = new NetworkMonitor(application);
networkMonitor.startNetworkMonitoring();
}
private void initBugly(Application application) {
CrashReport.initCrashReport(application, "1f100db6b7", true);
}
private void initEasyHttp(Application application) {
// 设置 Json 解析容错监听
GsonFactory.setParseExceptionCallback(new ParseExceptionCallback() {
@Override
public void onParseObjectException(TypeToken<?> typeToken, String fieldName, JsonToken jsonToken) {
handlerGsonParseException("解析对象析异常:" + typeToken + "#" + fieldName + ",后台返回的类型为:" + jsonToken);
}
@Override
public void onParseListItemException(TypeToken<?> typeToken, String fieldName, JsonToken listItemJsonToken) {
handlerGsonParseException("解析 List 异常:" + typeToken + "#" + fieldName + ",后台返回的条目类型为:" + listItemJsonToken);
}
@Override
public void onParseMapItemException(TypeToken<?> typeToken, String fieldName, String mapItemKey, JsonToken mapItemJsonToken) {
handlerGsonParseException("解析 Map 异常:" + typeToken + "#" + fieldName + ",mapItemKey = " + mapItemKey + ",后台返回的条目类型为:" + mapItemJsonToken);
}
private void handlerGsonParseException(String message) {
if (BuildConfig.DEBUG) {
throw new IllegalArgumentException(message);
} else {
CrashReport.postCatchedException(new IllegalArgumentException(message));
}
}
});
// 网络请求框架初始化
IRequestServer server;
if (BuildConfig.DEBUG) {
server = new TestServer();
} else {
server = new ReleaseServer();
}
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.build();
EasyConfig.with(okHttpClient)
// 是否打印日志
.setLogEnabled(BuildConfig.DEBUG)
// 设置服务器配置(必须设置)
.setServer(server)
// 设置请求处理策略(必须设置)
.setHandler(new RequestHandler(application))
// 设置请求参数拦截器
.setInterceptor(new IRequestInterceptor() {
@Override
public void interceptArguments(@NonNull HttpRequest<?> httpRequest,
@NonNull HttpParams params,
@NonNull HttpHeaders headers) {
headers.put("timestamp", String.valueOf(System.currentTimeMillis()));
headers.put("Authorization", "Bearer " + CacheUtil.getToken());
}
})
// 设置请求重试次数
.setRetryCount(1)
// 设置请求重试时间
.setRetryTime(2000)
// 添加全局请求参数
// .addParam("token", "6666666")
// 添加全局请求头
//.addHeader("date", "20191030")
.into();
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save