commit
ed3c4a4700
@ -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 |
@ -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)。修改频率极低。 |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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 |
@ -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" "$@" |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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…
Reference in new issue