ITAnt 3 éve
szülő
commit
d5792c351a
54 módosított fájl, 1064 hozzáadás és 412 törlés
  1. 7 1
      .gitignore
  2. 1 1
      app/.gitignore
  3. 115 14
      app/build.gradle
  4. BIN
      app/google.jks
  5. BIN
      app/libs/mvp.aar
  6. 35 0
      app/mvp.gradle
  7. 287 2
      app/proguard-rules.pro
  8. 22 0
      app/src/androidTest/java/com/itant/pay/ExampleInstrumentedTest.kt
  9. 0 26
      app/src/androidTest/java/com/itant/payhelper/ExampleInstrumentedTest.java
  10. 14 7
      app/src/main/AndroidManifest.xml
  11. 24 0
      app/src/main/java/com/itant/pay/App.kt
  12. 39 0
      app/src/main/java/com/itant/pay/base/BaseActivity.kt
  13. 27 0
      app/src/main/java/com/itant/pay/base/BaseFragment.kt
  14. 36 0
      app/src/main/java/com/itant/pay/ext/ViewExt.kt
  15. 16 0
      app/src/main/java/com/itant/pay/net/ApiManager.kt
  16. 21 0
      app/src/main/java/com/itant/pay/net/ApiService.kt
  17. 66 0
      app/src/main/java/com/itant/pay/net/BaseResponse.kt
  18. 22 0
      app/src/main/java/com/itant/pay/net/NetConstants.kt
  19. 18 8
      app/src/main/java/com/itant/payhelper/AlipayNotificationListenerService.java
  20. 32 0
      app/src/main/java/com/itant/pay/ui/main/MainActivity.kt
  21. 5 5
      app/src/main/java/com/itant/payhelper/NotificationCollectorMonitorService.java
  22. 0 41
      app/src/main/java/com/itant/payhelper/MainActivity.java
  23. 0 34
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  24. 0 170
      app/src/main/res/drawable/ic_launcher_background.xml
  25. 10 0
      app/src/main/res/drawable/ic_search.xml
  26. 10 0
      app/src/main/res/drawable/ic_settings.xml
  27. 58 9
      app/src/main/res/layout/activity_main.xml
  28. 8 0
      app/src/main/res/layout/view_divider.xml
  29. 0 5
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  30. 0 5
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  31. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  32. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  33. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  34. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  35. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  36. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  37. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  38. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  39. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  40. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  41. BIN
      app/src/main/res/mipmap-xxxhdpi/item_flashlight.png
  42. BIN
      app/src/main/res/mipmap-xxxhdpi/item_flashlight_switch.png
  43. 78 4
      app/src/main/res/values/colors.xml
  44. 2 2
      app/src/main/res/values/strings.xml
  45. 26 6
      app/src/main/res/values/styles.xml
  46. 16 0
      app/src/test/java/com/itant/pay/ExampleUnitTest.kt
  47. 0 17
      app/src/test/java/com/itant/payhelper/ExampleUnitTest.java
  48. 10 7
      build.gradle
  49. 9 5
      gradle.properties
  50. BIN
      gradle/wrapper/gradle-wrapper.jar
  51. 3 3
      gradle/wrapper/gradle-wrapper.properties
  52. 42 30
      gradlew
  53. 4 10
      gradlew.bat
  54. 1 0
      settings.gradle

+ 7 - 1
.gitignore

@@ -1,9 +1,15 @@
 *.iml
 .gradle
 /local.properties
-/.idea/workspace.xml
+/.idea/caches
 /.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
 .DS_Store
 /build
 /captures
 .externalNativeBuild
+.cxx
+local.properties

+ 1 - 1
app/.gitignore

@@ -1 +1 @@
-/build
+/build

+ 115 - 14
app/build.gradle

@@ -1,28 +1,129 @@
-apply plugin: 'com.android.application'
+plugins {
+    id 'com.android.application'
+    id 'kotlin-android'
+}
+apply from: 'mvp.gradle'
 
 android {
-    compileSdkVersion 27
+    compileSdkVersion 30
+    buildToolsVersion "30.0.3"
+
     defaultConfig {
-        applicationId "com.itant.payhelper"
-        minSdkVersion 19
-        targetSdkVersion 27
+        applicationId "com.itant.pay"
+        minSdkVersion 23
+        targetSdkVersion 30
         versionCode 1
         versionName "1.0"
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    // 开启ViewBinding
+    viewBinding {
+        enabled = true
+    }
+
+    signingConfigs {
+        config {
+            storeFile file('google.jks')
+            storePassword "Away6899458"
+            keyAlias "mm"
+            keyPassword "Away6899458"
+            v1SigningEnabled true
+            v2SigningEnabled true
+        }
     }
+
     buildTypes {
-        release {
+        debug {
+            signingConfig signingConfigs.config
             minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+
+            buildConfigField("String", "BASE_URL", '"http://www.shuiliu520.com/wuji/"')
+        }
+        release {
+            signingConfig signingConfigs.config
+            // 是否可调试
+            debuggable false
+            // 开启混淆
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+            // 打的aar包里会含有一个混淆文件,apk打包时该混淆文件会自动引用
+            consumerProguardFiles 'proguard-rules.pro'
+            //buildConfigField("String", "BASE_URL", '"http://erp.blueasiainfo.com:19291/"')
+
+            buildConfigField("String", "BASE_URL", '"http://www.shuiliu520.com/wuji/"')
+        }
+    }
+
+    // 设置apk文件名
+    android.applicationVariants.all { variant ->
+        variant.outputs.all {
+            outputFileName = "box_v${defaultConfig.versionName}.apk"
+            switch (variant.getName()) {
+                case "debug":
+                    outputFileName = "pay_debug_v${defaultConfig.versionName}.apk"
+                    break
+                case "release":
+                    outputFileName = "pay_realease_v${defaultConfig.versionName}.apk"
+                    break
+            }
         }
     }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
 }
 
 dependencies {
-    implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation 'com.android.support:appcompat-v7:27.1.1'
-    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+    //implementation 'com.itant.base:mvp:1.0.3'
+    implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
+
+    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+    implementation "androidx.core:core-ktx:1.3.1"
+    implementation "androidx.appcompat:appcompat:1.3.0"
+    implementation "com.google.android.material:material:1.3.0"
     testImplementation 'junit:junit:4.12'
-    androidTestImplementation 'com.android.support.test:runner:1.0.2'
-    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
-}
+    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+
+    // 工具
+    implementation 'com.blankj:utilcodex:1.31.0'
+
+    // 通知栏显示请求
+    debugImplementation 'com.readystatesoftware.chuck:library:1.1.0'
+    releaseImplementation 'com.readystatesoftware.chuck:library-no-op:1.1.0'
+
+    // RecyclerView
+    //implementation 'androidx.recyclerview:recyclerview:1.2.1'
+
+    // 适配器
+    //implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6'
+
+    // 下拉刷新
+    //implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
+
+    // 圆角图片
+    //implementation 'com.makeramen:roundedimageview:2.3.0'
+
+    // Glide加载图片
+    //api 'com.github.bumptech.glide:glide:4.11.0'
+    //annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
+
+    // 内存泄漏检测
+    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
+
+    // MMKV
+    //implementation 'com.tencent:mmkv-static:1.2.10'
+
+    //高德地图(保持旧的SDK,新的SDK需要弹出提示框同意协议,后续再做)
+    //implementation 'com.amap.api:location:4.7.2'
+    //implementation 'com.amap.api:map2d:5.2.0'
+    //implementation 'com.amap.api:3dmap:6.9.0'
+}

BIN
app/google.jks


BIN
app/libs/mvp.aar


+ 35 - 0
app/mvp.gradle

@@ -0,0 +1,35 @@
+dependencies {
+    
+    // 使用 retrofit + rx + gson 实现网络请求与解析
+    def retrofit_version = '2.9.0'
+    // 使用 retrofit + rx + gson 实现网络请求与解析---->
+    api "com.squareup.retrofit2:retrofit:$retrofit_version"
+    // 衔接 retrofit 和 rxjava
+    api 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
+    // 衔接 retrofit 和 gson
+    api 'com.squareup.retrofit2:converter-gson:2.8.1'
+
+    // 此处一定要注意使用RxJava2的版本,和Retrofit配合
+    api 'io.reactivex.rxjava2:rxjava:2.2.17'
+    api 'io.reactivex.rxjava2:rxandroid:2.1.1'
+
+    // GSON
+    api 'com.google.code.gson:gson:2.8.6'
+
+    // 打印网络请求日志框架
+    api "com.squareup.okhttp3:logging-interceptor:3.6.0"
+
+    // 通用设计
+    //api "androidx.appcompat:appcompat:${Config.google_appcompat}"
+    //api "com.google.android.material:material:${Config.google_material}"
+    api "androidx.activity:activity:1.2.0-beta01"
+    // ViewBinding
+    api 'androidx.databinding:viewbinding:4.2.0@aar'
+
+    // kotlin
+    api "androidx.lifecycle:lifecycle-extensions:2.2.0"
+    api "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+    api "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
+    api "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
+    api "androidx.preference:preference-ktx:1.1.1"
+}

+ 287 - 2
app/proguard-rules.pro

@@ -16,6 +16,291 @@
 # debugging stack traces.
 #-keepattributes SourceFile,LineNumberTable
 
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
+# 子Module是不需要混淆的,这是因为在主Module中配置了混淆,打包时会作用在所有的Module上,
+# 即其他的Module的代码也会被混淆,如果在子Module中再混淆,势必会导致找不到一些类的错误。
+
+# 注意:①所有经由网络JSON转换的实体类,必须实现Serializable且防止混淆!
+# 注意:②每新增一个开源库,就要导入相应的混淆规则!
+
+# 关闭代码优化
+-dontoptimize
+# 处理androidx包
+-dontnote androidx.**
+-dontwarn androidx.**
+# 保留继承的
+-keep public class * extends androidx.**
+-keep public class * extends android.app.Application
+# 保留四大组件,自定义的Application等这些类不被混淆
+-keep public class * extends android.app.Activity
+-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
+
+
+# google推荐算法
+-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
+# 压缩级别
+-optimizationpasses 5
+# 优化时允许访问并修改有修饰符的类及类的成员
+-allowaccessmodification
+
+# 混淆后类型都为小写
+-dontusemixedcaseclassnames
+# 混淆时记录日志
+-verbose
+-ignorewarnings
+-keep class javax.inject.** { *; }
+
+# 避免混淆Annotation
+-keepattributes *Annotation*
+# 防止拥有该成员的类和类成员被混淆
+-keepclasseswithmembernames class * {
+    native <methods>;
+}
+-keepclasseswithmembers class * {
+    native <methods>;
+}
+-keepclassmembers class * {
+    native <methods>;
+}
+
+# 不混淆自定义View
+-keepclassmembers public class * extends android.view.View {
+   void set*(***);
+   *** get*();
+}
+-keepclasseswithmembers class * {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+# 不混淆Activity里的方法,这样就可以在xml的onClick里使用该方法了
+#-keepclassmembers class * extends android.app.Activity {
+#   public void *(android.view.View);
+#}
+
+# 不混淆枚举
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+# 不混淆Parcelable子类
+-keepclassmembers class * implements android.os.Parcelable {
+  public static final android.os.Parcelable$Creator CREATOR;
+}
+
+# 保留R下面的资源
+-keepclassmembers class **.R$* {
+    public static <fields>;
+}
+-keep class **.R$* {*;}
+
+# The support library contains references to newer platform versions.
+# Don't warn about those in case this app is linking against an older
+# platform version.  We know about them, and they are safe.
+-dontwarn android.support.**
+
+# 不混淆Keep注解标记的类
+-keep class androidx.annotation.Keep
+-keep @androidx.annotation.Keep class * {*;}
+-keepclasseswithmembers class * {
+    @androidx.annotation.Keep <methods>;
+}
+-keepclasseswithmembers class * {
+    @androidx.annotation.Keep <fields>;
+}
+-keepclasseswithmembers class * {
+    @androidx.annotation.Keep <init>(...);
+}
+
+# 将源码中有意义的类名转换成SourceFile,用于混淆具体崩溃代码
 #-renamesourcefileattribute SourceFile
+# 抛出异常时保留代码行号
+#-renamesourcefileattribute flooSDK
+#-keepattributes SourceFile,LineNumberTable
+#-keepattributes Exceptions,InnerClasses,Signature,EnclosingMethod
+
+# 图片选择 PictureSelector 2.0
+-keep class com.luck.picture.lib.** { *; }
+
+# 城市选择
+-keep class com.lljjcoder.**{
+	*;
+}
+-dontwarn demo.**
+-keep class demo.**{*;}
+-dontwarn net.sourceforge.pinyin4j.**
+-keep class net.sourceforge.pinyin4j.**{*;}
+-keep class net.sourceforge.pinyin4j.format.**{*;}
+-keep class net.sourceforge.pinyin4j.format.exception.**{*;}
+
+# RxJava RxAndroid
+-dontwarn sun.misc.**
+-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
+    long producerIndex;
+    long consumerIndex;
+}
+-dontwarn com.tbruyelle.rxpermissions.**
+
+# Android源码
+-keep class com.google.android.material.** { *; }
+-dontwarn com.google.android.material.**
+-dontnote com.google.android.material.**
+-keep class com.google.** { *; }
+-dontwarn androidx.**
+-keep interface androidx.** { *; }
+-keep class androidx.** {*;}
+-keep class com.google.** { *; }
+-keep interface com.google.** { *; }
+-dontwarn com.google.**
+-keep class com.google.protobuf.* {*;}
+-dontwarn com.google.protobuf.**
+
+# 一些开源项目
+-keep class com.github.** { *; }
+-keep class com.wangjie.** { *; }
+-keep class com.bigkoo.** { *; }
+-keep class com.blankj.** { *; }
+-keep class com.miekir.** { *; }
+
+# okhttp
+# A resource is loaded with a relative path so the package of this class must be preserved.
+-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
+# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
+-dontwarn org.codehaus.mojo.animal_sniffer.*
+# OkHttp platform used only on JVM and when Conscrypt dependency is available.
+-dontwarn okhttp3.internal.platform.ConscryptPlatform
+-dontwarn org.conscrypt.ConscryptHostnameVerifier
+-dontwarn okio.**
+-keep class com.squareup.okhttp.** { *;}
+-dontwarn com.squareup.okhttp.**
+-dontwarn javax.annotation.**
+-keep class okhttp3.** { *; }
+-keep interface okhttp3.** { *; }
+-dontwarn okhttp3.**
+
+# Retrofit
+-keep class retrofit2.** { *; }
+-keep interface retrofit2.** { *; }
+-dontwarn retrofit2.**
+-keepattributes Signature, InnerClasses, EnclosingMethod
+# Retrofit does reflection on method and parameter annotations.
+-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
+# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
+-keepattributes AnnotationDefault
+# Retain service method parameters when optimizing.
+-keepclassmembers,allowshrinking,allowobfuscation interface * {
+    @retrofit2.http.* <methods>;
+}
+# Ignore annotation used for build tooling.
+-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
+# Ignore JSR 305 annotations for embedding nullability information.
+-dontwarn javax.annotation.**
+# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
+-dontwarn kotlin.Unit
+# Top-level functions that can only be used by Kotlin.
+-dontwarn retrofit2.KotlinExtensions
+-dontwarn retrofit2.KotlinExtensions$*
+# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
+# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
+-if interface * { @retrofit2.http.* <methods>; }
+-keep,allowobfuscation interface <1>
+# Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items).
+-keep,allowobfuscation,allowshrinking interface retrofit2.Call
+-keep,allowobfuscation,allowshrinking class retrofit2.Response
+# With R8 full mode generic signatures are stripped for classes that are not
+# kept. Suspend functions are wrapped in continuations where the type argument
+# is used.
+-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
+
+# LeakCanary
+-dontwarn com.squareup.haha.guava.**
+-dontwarn com.squareup.haha.perflib.**
+-dontwarn com.squareup.haha.trove.**
+-dontwarn com.squareup.leakcanary.**
+-keep class com.squareup.** { *; }
+-keep class leakcanary.** { *; }
+# Marshmallow removed Notification.setLatestEventInfo()
+-dontwarn android.app.Notification
+
+# Glide
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep class * extends com.bumptech.glide.module.AppGlideModule {
+ <init>(...);
+}
+-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
+  **[] $VALUES;
+  public *;
+}
+-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
+  *** rewind();
+}
+
+# GSON
+-keep class * extends com.google.gson.TypeAdapter
+-keep class * implements com.google.gson.TypeAdapterFactory
+-keep class * implements com.google.gson.JsonSerializer
+-keep class * implements com.google.gson.JsonDeserializer
+-keep class org.json.* {*;}
+
+# BaseQuickAdapter
+-keep class com.chad.library.adapter.** {
+*;
+}
+-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
+
+# AutoSize
+-keep class com.miekir.common.autosize.** { *; }
+-keep interface com.miekir.common.autosize.** { *; }
+
+#kotlin
+-dontwarn org.jetbrains.**
+-dontwarn com.ted.floo.**
+-keep class org.jetbrains.** { *; }
+-keep interface org.jetbrains.** { *; }
+-keep class kotlin.** { *; }
+-keep interface kotlin.** { *; }
+-keepclassmembers class kotlin.Metadata {
+    public <methods>;
+}
+-keepclassmembers class **.WhenMappings {
+    <fields>;
+}
+-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
+    static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
+}
+-dontwarn kotlin.**
+-keep class kotlinx.** { *; }
+-keep interface kotlinx.** { *; }
+-dontwarn kotlinx.**
+# lateinit变量
+-keepclasseswithmembers @kotlin.Metadata class * { *; }
+-keep @kotlin.Metadata class *
+
+# 饺子播放器
+-keep public class cn.jzvd.JZMediaSystem {*; }
+# ijk播放器
+-keep class tv.danmaku.ijk.media.player.** {*; }
+-dontwarn tv.danmaku.ijk.media.player.*
+-keep interface tv.danmaku.ijk.media.player.** { *; }
+
+-dontwarn com.tencent.bugly.**
+-keep public class com.tencent.bugly.**{*;}
+
+# 高德地图
+# 定位
+-keep class com.amap.api.location.**{*;}
+-keep class com.amap.api.fence.**{*;}
+-keep class com.loc.**{*;}
+-keep class com.autonavi.aps.amapapi.model.**{*;}
+-dontwarn com.amap.api.**
+-dontwarn com.autonavi.**
+-keep class com.amap.api.**  {*;}
+-keep class com.autonavi.**  {*;}
+# 搜索
+-keep class com.amap.api.services.**{*;}
+# 2D地图
+-keep class com.amap.api.maps2d.**{*;}
+-keep class com.amap.api.mapcore2d.**{*;}

+ 22 - 0
app/src/androidTest/java/com/itant/pay/ExampleInstrumentedTest.kt

@@ -0,0 +1,22 @@
+package com.itant.pay
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.itant.treasurebox", appContext.packageName)
+    }
+}

+ 0 - 26
app/src/androidTest/java/com/itant/payhelper/ExampleInstrumentedTest.java

@@ -1,26 +0,0 @@
-package com.itant.payhelper;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.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() throws Exception {
-        // Context of the app under test.
-        Context appContext = InstrumentationRegistry.getTargetContext();
-
-        assertEquals("com.itant.payhelper", appContext.getPackageName());
-    }
-}

+ 14 - 7
app/src/main/AndroidManifest.xml

@@ -1,31 +1,38 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.itant.payhelper">
+    package="com.itant.pay">
+
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
 
     <application
         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=".MainActivity">
+        android:requestLegacyExternalStorage="true"
+        android:theme="@style/AppTheme"
+        android:name="com.itant.pay.App">
+        <activity android:name="com.itant.pay.ui.main.MainActivity"
+            android:exported="true"
+            android:configChanges="locale|orientation|screenSize|keyboardHidden"
+            android:screenOrientation="portrait">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-
+                <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
 
         <service
-            android:name=".AlipayNotificationListenerService"
+            android:exported="false"
+            android:name=".ui.main.AlipayService"
             android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
             <intent-filter>
                 <action android:name="android.service.notification.NotificationListenerService" />
             </intent-filter>
         </service>
 
-        <service android:name=".NotificationCollectorMonitorService"/>
+        <service android:name=".ui.main.MonitorService" />
     </application>
 
 </manifest>

+ 24 - 0
app/src/main/java/com/itant/pay/App.kt

@@ -0,0 +1,24 @@
+package com.itant.pay
+
+import android.app.Application
+import com.blankj.utilcode.util.AppUtils
+import com.miekir.mvp.view.anim.SlideAnimation
+import com.miekir.task.MvpManager
+import com.miekir.task.net.RetrofitManager
+import com.readystatesoftware.chuck.ChuckInterceptor
+
+/**
+ * @date 2021-8-28 15:26
+ * @author 詹子聪
+ */
+class App: Application() {
+    override fun onCreate() {
+        super.onCreate()
+
+        // MVP相关设置
+        MvpManager.getInstance().activityAnimation(SlideAnimation())
+        RetrofitManager.getDefault()
+            .addInterceptors(ChuckInterceptor(this))
+            .printLog(AppUtils.isAppDebug())
+    }
+}

+ 39 - 0
app/src/main/java/com/itant/pay/base/BaseActivity.kt

@@ -0,0 +1,39 @@
+package com.itant.pay.base
+
+import android.os.Bundle
+import androidx.viewbinding.ViewBinding
+import com.blankj.utilcode.util.KeyboardUtils
+import com.blankj.utilcode.util.ScreenUtils
+import com.itant.mvp.kt.extension.enableHighRefreshRate
+import com.miekir.mvp.view.binding.adapt.BindingActivity
+
+/**
+ * @date 2022-1-16 20:52
+ * @author 詹子聪
+ */
+abstract class BaseActivity<VB : ViewBinding> : BindingActivity<VB>() {
+    companion object {
+        const val SIZE_IN_DP_WIDTH = 375.0f
+    }
+
+    override fun isBaseOnWidth(): Boolean {
+        return ScreenUtils.getScreenWidth() < ScreenUtils.getAppScreenHeight()
+    }
+
+    override fun getSizeInDp(): Float {
+        return SIZE_IN_DP_WIDTH
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        touchSpaceHideKeyboard = true
+        // 启用高刷新率
+        enableHighRefreshRate()
+        super.onCreate(savedInstanceState)
+    }
+
+    override fun onPause() {
+        // 必须要在onPause隐藏键盘,在onDestroy就太晚了
+        KeyboardUtils.hideSoftInput(this)
+        super.onPause()
+    }
+}

+ 27 - 0
app/src/main/java/com/itant/pay/base/BaseFragment.kt

@@ -0,0 +1,27 @@
+package com.itant.pay.base
+
+import android.os.Bundle
+import android.view.View
+import androidx.viewbinding.ViewBinding
+import com.blankj.utilcode.util.ScreenUtils
+import com.miekir.mvp.view.binding.adapt.BindingFragment
+
+/**
+ * 基础Fragment
+ * @date 2021-8-26 22:33
+ * @author 詹子聪
+ */
+abstract class BaseFragment<VB : ViewBinding> : BindingFragment<VB>() {
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+    }
+
+    override fun getSizeInDp(): Float {
+        return BaseActivity.SIZE_IN_DP_WIDTH
+    }
+
+    override fun isBaseOnWidth(): Boolean {
+        return ScreenUtils.getScreenWidth() < ScreenUtils.getScreenHeight()
+    }
+}

+ 36 - 0
app/src/main/java/com/itant/pay/ext/ViewExt.kt

@@ -0,0 +1,36 @@
+package com.itant.pay.ext
+
+import android.app.Dialog
+import android.text.TextUtils
+import android.widget.TextView
+import com.blankj.utilcode.util.ScreenUtils
+import com.itant.pay.base.BaseActivity.Companion.SIZE_IN_DP_WIDTH
+import com.miekir.common.autosize.AutoSizeCompat
+import com.miekir.common.tools.ToastTools
+
+/**
+ * 获取文本
+ */
+fun TextView.getString(message: String? = null): String? {
+    val text = this.text.toString()
+    if (TextUtils.isEmpty(text)) {
+        if (!TextUtils.isEmpty(message)) {
+            ToastTools.showShort(message)
+        }
+        return null
+    }
+    return text
+}
+
+/**
+ * 适配对话框
+ */
+fun Dialog.showAdapt() {
+    val width = if (ScreenUtils.getScreenWidth() < ScreenUtils.getScreenHeight()) {
+        SIZE_IN_DP_WIDTH
+    } else {
+        SIZE_IN_DP_WIDTH * ScreenUtils.getScreenWidth() * 1.0f / ScreenUtils.getScreenHeight()
+    }
+    AutoSizeCompat.autoConvertDensity(context.resources, width, ScreenUtils.getScreenWidth() < ScreenUtils.getScreenHeight())
+    show()
+}

+ 16 - 0
app/src/main/java/com/itant/pay/net/ApiManager.kt

@@ -0,0 +1,16 @@
+package com.itant.pay.net
+
+import com.itant.pay.BuildConfig
+import com.miekir.task.net.RetrofitManager
+
+/**
+ * 网络请求封装
+ * @date 2021-8-7 11:32
+ * @author 詹子聪
+ */
+object ApiManager {
+    /**
+     * 默认的网络请求
+     */
+    val default = RetrofitManager.getDefault().createApiService(BuildConfig.BASE_URL, ApiService::class.java)
+}

+ 21 - 0
app/src/main/java/com/itant/pay/net/ApiService.kt

@@ -0,0 +1,21 @@
+package com.itant.pay.net
+
+import retrofit2.http.GET
+import retrofit2.http.Query
+
+
+/**
+ * 请求接口
+ * @date 2021-8-7 11:36
+ * @author 詹子聪
+ */
+interface ApiService {
+
+    /**
+     * 获取验证码接口
+     */
+    @GET("prod-api/api/login/smsCode")
+    suspend fun sendSmsCode(@Query("phone") phone: String): BaseResponse<Any>
+
+
+}

+ 66 - 0
app/src/main/java/com/itant/pay/net/BaseResponse.kt

@@ -0,0 +1,66 @@
+package com.itant.pay.net
+
+import androidx.annotation.Keep
+import com.miekir.task.net.IResponse
+
+/**
+ * 统一返回封装
+ */
+@Keep
+class BaseResponse<T> : IResponse {
+    /**
+     * 返回状态代码
+     */
+    var code = NetConstants.SUCCESS
+
+    /**
+     * 消息
+     */
+    var msg: String? = null
+
+    /**
+     * 返回的实体数据
+     */
+    var data: T? = null
+
+    companion object {
+        @Transient
+        private var sLastJumpMillis = 0L
+    }
+
+    override fun getServerMessage(): String? {
+        return msg
+    }
+
+    /**
+     * 校验返回信息,如果没有错误也没有过期就返回true,如果有错误则抛出异常即可
+     * 防止有些不需要使用到结果的接口不断提交失败,及时发现隐藏的重大错误如登录过期等
+     */
+    override fun valid(): Boolean {
+        if (code != NetConstants.SUCCESS) {
+            /*if (code == NetConstants.EXPIRED && (System.currentTimeMillis()-sLastJumpMillis) > 2000L) {
+                //ToastUtils.showShort("请重新登录")
+                val topActivity = ActivityUtils.getTopActivity()
+                if (topActivity != null) {
+                    if (topActivity !is LoginActivity) {
+                        sLastJumpMillis = System.currentTimeMillis()
+                        val intent = Intent(GlobalContext.getContext(), LoginActivity::class.java)
+                        intent.putExtra(LoginActivity.KEY_EXPIRED, true)
+                        topActivity.startActivity(intent)
+                        if (topActivity !is MachineActivity) {
+                            topActivity.finish()
+                        }
+                    }
+                } else {
+                    sLastJumpMillis = System.currentTimeMillis()
+                    val intent = Intent(GlobalContext.getContext(), LoginActivity::class.java)
+                    intent.putExtra(LoginActivity.KEY_EXPIRED, true)
+                    intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TOP
+                    GlobalContext.getContext().startActivity(intent)
+                }
+            }
+            throw ExceptionResult(code, msg)*/
+        }
+        return true
+    }
+}

+ 22 - 0
app/src/main/java/com/itant/pay/net/NetConstants.kt

@@ -0,0 +1,22 @@
+package com.itant.pay.net
+
+/**
+ * @date 2021-8-20 22:05
+ * @author 詹子聪
+ */
+object NetConstants {
+    const val PAGE_SIZE     = 20
+    const val PAGE_START    = 1
+    const val URL_PREFIX = "http"
+
+    /**
+     * 响应成功的code
+     */
+    const val SUCCESS       = 200
+
+    /**
+     * token过期,没有访问权限
+     */
+    const val EXPIRED       = 401
+
+}

+ 18 - 8
app/src/main/java/com/itant/payhelper/AlipayNotificationListenerService.java

@@ -1,6 +1,9 @@
-package com.itant.payhelper;
+package com.itant.pay.ui.main;
 
 import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
@@ -9,13 +12,13 @@ import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 
+import com.miekir.common.log.L;
+
 /**
  * 使用注意事项:你可以直接debug运行,然后可以监听到通知。但是,如果你是先run,然后开启通知权限,然后再debug,就监听不到了。
  */
-public class AlipayNotificationListenerService extends NotificationListenerService {
-    public AlipayNotificationListenerService() {
-
-    }
+public class AlipayService extends NotificationListenerService {
+    public static final String CHANNEL_ID_STRING = "money_alipay";
 
     @Override
     public void onNotificationRemoved(StatusBarNotification sbn) {
@@ -36,12 +39,14 @@ public class AlipayNotificationListenerService extends NotificationListenerServi
         if (notification == null) {
             return;
         }
-        if (Build.VERSION.SDK_INT >= 19 && packageName.contains("alipay")) {
+        if (packageName.contains("alipay")) {
             Bundle extras = notification.extras;
             if (extras != null) {
-                // 这里是具体的title和content,可以从中提取金额
+                // 这里是具体的title和content,可以从中提取金额title:你已成功收款0.01元 content:已转入余额 用收钱码收钱,提现免费>>
+                // 就保持这个方式启动服务,然后允许后台自启,允许监听,支付宝位于前台,关闭OPPO辅助收款通知,使用支付宝原生的提醒音
                 String title = extras.getString(Notification.EXTRA_TITLE, "");
                 String content = extras.getString(Notification.EXTRA_TEXT, "");
+                L.e("alipay", "title:" + title + " content:" + content);
                 // todo 发送请求给服务器,告诉服务器,当前列表里的用户支付成功,发送推送
             }
         }
@@ -49,12 +54,17 @@ public class AlipayNotificationListenerService extends NotificationListenerServi
 
     @Override
     public void onListenerConnected() {
-        Log.e("shiwushu_alipay","失物树已连接监听");
+        Log.e("alipay","失物树已连接监听");
     }
 
     @Override
     public void onListenerDisconnected() {
         super.onListenerDisconnected();
     }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        return START_STICKY;
+    }
 }
 

+ 32 - 0
app/src/main/java/com/itant/pay/ui/main/MainActivity.kt

@@ -0,0 +1,32 @@
+package com.itant.pay.ui.main
+
+import android.content.ComponentName
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.provider.Settings
+import com.itant.pay.base.BaseActivity
+import com.itant.pay.databinding.ActivityMainBinding
+
+
+/**
+ * 首页
+ */
+class MainActivity : BaseActivity<ActivityMainBinding>() {
+
+    override fun onBindingInflate() = ActivityMainBinding.inflate(layoutInflater)
+
+    override fun onInit() {
+    }
+
+    override fun onResume() {
+        super.onResume()
+        if (Settings.Secure.getString(this.contentResolver, "enabled_notification_listeners").contains(applicationContext.packageName)) {
+            //Add the code to launch the NotificationService Listener here.
+            startService(Intent(this, AlipayService::class.java))
+        } else {
+            //Launch notification access in the settings...
+            startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
+        }
+    }
+}

+ 5 - 5
app/src/main/java/com/itant/payhelper/NotificationCollectorMonitorService.java

@@ -1,4 +1,4 @@
-package com.itant.payhelper;
+package com.itant.pay.ui.main;
 
 import android.app.ActivityManager;
 import android.app.Service;
@@ -21,14 +21,14 @@ import java.util.List;
  * BY THE WAY Don't Forget to Add the Service to the AndroidManifest.xml File.
  * <service android:name=".NotificationCollectorMonitorService"/>
  */
-public class NotificationCollectorMonitorService extends Service {
+public class MonitorService extends Service {
 
     /**
      * {@link Log#isLoggable(String, int)}
      * <p>
      * IllegalArgumentException is thrown if the tag.length() > 23.
      */
-    private static final String TAG = "NotifiCollectorMonitor";
+    private static final String TAG = "MonitorService";
 
     @Override
     public void onCreate() {
@@ -43,7 +43,7 @@ public class NotificationCollectorMonitorService extends Service {
     }
 
     private void ensureCollectorRunning() {
-        ComponentName collectorComponent = new ComponentName(this, /*NotificationListenerService Inheritance*/ com.itant.payhelper.NotificationCollectorMonitorService.class);
+        ComponentName collectorComponent = new ComponentName(this, /*NotificationListenerService Inheritance*/ MonitorService.class);
         Log.v(TAG, "ensureCollectorRunning collectorComponent: " + collectorComponent);
         ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
         boolean collectorRunning = false;
@@ -71,7 +71,7 @@ public class NotificationCollectorMonitorService extends Service {
 
     private void toggleNotificationListenerService() {
         Log.d(TAG, "toggleNotificationListenerService() called");
-        ComponentName thisComponent = new ComponentName(this, /*getClass()*/ com.itant.payhelper.NotificationCollectorMonitorService.class);
+        ComponentName thisComponent = new ComponentName(this, MonitorService.class);
         PackageManager pm = getPackageManager();
         pm.setComponentEnabledSetting(thisComponent, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
         pm.setComponentEnabledSetting(thisComponent, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

+ 0 - 41
app/src/main/java/com/itant/payhelper/MainActivity.java

@@ -1,41 +0,0 @@
-package com.itant.payhelper;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.support.v7.app.AppCompatActivity;
-import android.widget.TextView;
-
-public class MainActivity extends AppCompatActivity {
-
-    private TextView tv_test;
-    private boolean payListenerStarted;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_main);
-
-        tv_test = findViewById(R.id.tv_test);
-        if (Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners").contains(getApplicationContext().getPackageName())) {
-            //Add the code to launch the NotificationService Listener here.
-            tv_test.setText("已经拥有获取通知的权限");
-            if (!payListenerStarted) {
-                startService(new Intent(this, AlipayNotificationListenerService.class));
-                payListenerStarted = true;
-            }
-        } else {
-            //Launch notification access in the settings...
-            tv_test.setText("请设置通知权限");
-            startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
-        }
-
-        //startService(new Intent(this, NotificationCollectorMonitorService.class));
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-
-    }
-}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 34
app/src/main/res/drawable-v24/ic_launcher_foreground.xml


+ 0 - 170
app/src/main/res/drawable/ic_launcher_background.xml

@@ -1,170 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="108dp"
-    android:height="108dp"
-    android:viewportHeight="108"
-    android:viewportWidth="108">
-    <path
-        android:fillColor="#26A69A"
-        android:pathData="M0,0h108v108h-108z" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M9,0L9,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,0L19,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M29,0L29,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M39,0L39,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M49,0L49,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M59,0L59,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M69,0L69,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M79,0L79,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M89,0L89,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M99,0L99,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,9L108,9"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,19L108,19"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,29L108,29"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,39L108,39"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,49L108,49"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,59L108,59"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,69L108,69"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,79L108,79"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,89L108,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,99L108,99"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,29L89,29"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,39L89,39"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,49L89,49"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,59L89,59"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,69L89,69"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,79L89,79"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M29,19L29,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M39,19L39,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M49,19L49,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M59,19L59,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M69,19L69,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M79,19L79,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-</vector>

+ 10 - 0
app/src/main/res/drawable/ic_search.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
+</vector>

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 10 - 0
app/src/main/res/drawable/ic_settings.xml


+ 58 - 9
app/src/main/res/layout/activity_main.xml

@@ -1,16 +1,65 @@
 <?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout 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:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context="com.itant.payhelper.MainActivity">
+    android:orientation="vertical">
 
-    <TextView
-        android:id="@+id/tv_test"
-        android:layout_centerInParent="true"
-        android:layout_width="wrap_content"
+    <include layout="@layout/view_divider" />
+
+    <!--父布局加了背景色,selectableItemBackgroundBorderless就不会越界了-->
+    <FrameLayout
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:text="Hello World!" />
+        android:background="@color/colorPrimary"
+        android:minHeight="46dp">
+
+        <FrameLayout
+            android:id="@+id/view_settings"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start|center_vertical"
+            android:background="?android:selectableItemBackgroundBorderless"
+            android:minHeight="48dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
+            android:visibility="gone">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:src="@drawable/ic_settings"
+                app:tint="@color/gray_text_s" />
+        </FrameLayout>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/app_name"
+            android:textColor="@color/black_text"
+            android:textSize="18sp" />
+
+        <FrameLayout
+            android:id="@+id/view_search"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end|center_vertical"
+            android:background="?android:selectableItemBackgroundBorderless"
+            android:minHeight="48dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
+            android:visibility="gone">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:src="@drawable/ic_search"
+                app:tint="@color/gray_text_s" />
+        </FrameLayout>
+    </FrameLayout>
 
-</RelativeLayout>
+    <include layout="@layout/view_divider" />
+</LinearLayout>

+ 8 - 0
app/src/main/res/layout/view_divider.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="@color/gray_divider_light_s" />
+</merge>

+ 0 - 5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@drawable/ic_launcher_background" />
-    <foreground android:drawable="@drawable/ic_launcher_foreground" />
-</adaptive-icon>

+ 0 - 5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@drawable/ic_launcher_background" />
-    <foreground android:drawable="@drawable/ic_launcher_foreground" />
-</adaptive-icon>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxxhdpi/item_flashlight.png


BIN
app/src/main/res/mipmap-xxxhdpi/item_flashlight_switch.png


+ 78 - 4
app/src/main/res/values/colors.xml

@@ -1,6 +1,80 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <color name="colorPrimary">#3F51B5</color>
-    <color name="colorPrimaryDark">#303F9F</color>
-    <color name="colorAccent">#FF4081</color>
-</resources>
+
+    <color name="white_light">#FFFFFF</color>
+
+    <color name="gray">#ededed</color>
+    <color name="grayDark">#adadad</color>
+    <color name="gray_text_1">#62656A</color>
+    <color name="gray_text_2">#5F6267</color>
+    <color name="gray_normal">#6D6D6D</color>
+    <color name="gray_hint">#81868B</color>
+    <color name="gray_status_bar">#C1C1C1</color>
+    <color name="gray_divider_1">#E0E0E0</color>
+    <color name="gray_divider_2">#adadad</color>
+    <color name="gray_disabled">#4DFFFFFF</color>
+    <color name="gray_text">#222222</color>
+    <color name="gray_bg_default">#F3F3F3</color>
+    <color name="gray_status_bar_2">#C8C8C8</color>
+    <!-- 内容文字,正文 -->
+    <color name="gray_text_s">#777777</color>
+    <!-- 辅助文字,提示 -->
+    <color name="gray_text_hint">#ababab</color>
+    <!--<color name="gray_light">#CCCCCC</color>-->
+    <!-- 分割线 -->
+    <color name="gray_divider_light">#d9d9d9</color>
+    <color name="gray_divider_light_transparent">#80D9D9D9</color>
+    <color name="gray_divider_light_s">#ebebeb</color>
+    <color name="gray_divider_light_ss">#eeeeee</color>
+    <!--<color name="gray_divider_light_ss">#f0f0f0</color>-->
+    <color name="gray_loading">#26E0E0E0</color>
+    <color name="gray_tab_unchecked">#717171</color>
+
+    <color name="black_light">#252525</color>
+    <color name="black_light_transparent">#6B1B1B1B</color>
+    <color name="black_dark">#1b1b1b</color>
+    <color name="black_standard">#333333</color>
+    <color name="black_title">#5F6267</color>
+    <color name="black_text">#3C4043</color>
+    <color name="black_text_hint">#A6A6A6</color>
+    <color name="black_text_comfortable">#565656</color>
+
+    <color name="orange_text">#F96650</color>
+
+
+    <color name="colorPrimary">#fafafa</color>
+    <color name="colorPrimaryDark">#fafafa</color>
+    <color name="colorAccent">#fafafa</color>
+
+    <color name="white">#FFFFFF</color>
+    <color name="white_icon_light">#fbfbfb</color>
+    <color name="white_button">@color/gray_indicator</color>
+
+    <color name="black">#000000</color>
+    <color name="black_back">#444444</color>
+    <color name="black_icon">#545E60</color>
+
+    <color name="green_bright">#00e478</color>
+    <color name="green">#4CB050</color>
+    <color name="green_bg">#b5d8b7</color>
+    <color name="green_flag">#e8f6e9</color>
+
+    <color name="gray_text3">#afafaf</color>
+    <color name="gray_text2">#b5b5b5</color>
+    <color name="gray_text1">#D0D0D0</color>
+    <color name="gray_icon">#d8d8d8</color>
+    <color name="gray_bg">#F4F2F3</color>
+    <color name="gray_flag">#f5f5f5</color>
+    <color name="gray_indicator">#f8f8f8</color>
+
+    <color name="blue_dark">#100c2d</color>
+    <color name="blue_light">#565678</color>
+
+    <color name="yellow">#fed930</color>
+
+    <color name="green_what">#008069</color>
+    <color name="green_what_second">#00a884</color>
+    <color name="green_what_light">#d8fdd2</color>
+    <color name="white_what_text">#b4d9d2</color>
+    <color name="blue_what">#1ebea6</color>
+</resources>

+ 2 - 2
app/src/main/res/values/strings.xml

@@ -1,3 +1,3 @@
 <resources>
-    <string name="app_name">失物助手</string>
-</resources>
+    <string name="app_name">支付通知</string>
+</resources>

+ 26 - 6
app/src/main/res/values/styles.xml

@@ -1,11 +1,31 @@
 <resources>
-
     <!-- Base application theme. -->
-    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
-        <!-- Customize your theme here. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
         <item name="colorPrimary">@color/colorPrimary</item>
-        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
-        <item name="colorAccent">@color/colorAccent</item>
+        <item name="colorPrimaryDark">@color/colorPrimary</item>
+        <item name="colorAccent">@color/colorPrimary</item>
+        <item name="android:windowDisablePreview">true</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowActionBar">false</item>
+        <!--解决全屏的时候底部content和导航栏之间有一根白线的现象-->
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowBackground">@color/colorPrimary</item>
+        <!--状态栏文字黑色-->
+        <item name="android:windowLightStatusBar">true</item>
     </style>
 
-</resources>
+    <!--适配AlertDialog-->
+    <!--AutoSizeCompat.autoConvertDensity(context.resources, width, ScreenUtils.getScreenWidth() < ScreenUtils.getScreenHeight())-->
+    <style name="AdaptAlertDialog" parent="Theme.AppCompat.Dialog.Alert">
+        <item name ="android:background">@color/colorPrimary</item>
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimary</item>
+        <item name="colorAccent">@color/orange_text</item>
+        <!--<item name="android:textColor">#000000</item>-->
+        <!--message颜色-->
+        <item name="android:textColorPrimary">@color/black_text_comfortable</item>
+        <!-- Minor指竖屏模式下的宽度 -->
+        <item name="android:windowMinWidthMinor">375dp</item>
+        <item name="windowFixedWidthMinor">375dp</item>
+    </style>
+</resources>

+ 16 - 0
app/src/test/java/com/itant/pay/ExampleUnitTest.kt

@@ -0,0 +1,16 @@
+package com.itant.pay
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+    @Test
+    fun addition_isCorrect() {
+        assertEquals(4, 2 + 2)
+    }
+}

+ 0 - 17
app/src/test/java/com/itant/payhelper/ExampleUnitTest.java

@@ -1,17 +0,0 @@
-package com.itant.payhelper;
-
-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() throws Exception {
-        assertEquals(4, 2 + 2);
-    }
-}

+ 10 - 7
build.gradle

@@ -1,14 +1,13 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
-
 buildscript {
-    
+    ext.kotlin_version = "1.4.10"
     repositories {
         google()
-        jcenter()
+        mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.0.1'
-        
+        classpath "com.android.tools.build:gradle:4.2.0"
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
@@ -17,11 +16,15 @@ buildscript {
 
 allprojects {
     repositories {
+        mavenLocal{url "file://E://maven/local/repository/" }
+        maven { url "https://jitpack.io" }
+        maven { url "https://maven.aliyun.com/repository/public" }
         google()
-        jcenter()
+        mavenCentral()
+        jcenter() // Warning: this repository is going to shut down soon
     }
 }
 
 task clean(type: Delete) {
     delete rootProject.buildDir
-}
+}

+ 9 - 5
gradle.properties

@@ -1,17 +1,21 @@
 # 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=-Xmx1536m
-
+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
+android.enableJetifier=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+android.injected.testOnly=false

BIN
gradle/wrapper/gradle-wrapper.jar


+ 3 - 3
gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
-#Mon Oct 01 22:32:27 CST 2018
+#Sun Jan 16 19:37:40 CST 2022
 distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
 distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
+zipStoreBase=GRADLE_USER_HOME

+ 42 - 30
gradlew

@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
 
 ##############################################################################
 ##
@@ -6,20 +6,38 @@
 ##
 ##############################################################################
 
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# 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 ( ) {
+warn () {
     echo "$*"
 }
 
-die ( ) {
+die () {
     echo
     echo "$*"
     echo
@@ -30,6 +48,7 @@ die ( ) {
 cygwin=false
 msys=false
 darwin=false
+nonstop=false
 case "`uname`" in
   CYGWIN* )
     cygwin=true
@@ -40,26 +59,11 @@ case "`uname`" in
   MINGW* )
     msys=true
     ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
 esac
 
-# 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
-
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
 # Determine the Java command to use to start the JVM.
@@ -85,7 +89,7 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+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
@@ -150,11 +154,19 @@ if $cygwin ; then
     esac
 fi
 
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
-    JVM_OPTS=("$@")
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
 }
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+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" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"

+ 4 - 10
gradlew.bat

@@ -8,14 +8,14 @@
 @rem Set local scope for the variables with windows NT shell
 if "%OS%"=="Windows_NT" setlocal
 
-@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=
-
 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
 
@@ -46,10 +46,9 @@ echo location of your Java installation.
 goto fail
 
 :init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
 
 if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
 
 :win9xME_args
 @rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
 if "x%~1" == "x" goto execute
 
 set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
 
 :execute
 @rem Setup the command line

+ 1 - 0
settings.gradle

@@ -1 +1,2 @@
+rootProject.name = "TemplateProject"
 include ':app'