@onekeyfe/react-native-lite-card 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +37 -0
  3. package/ReactNativeLiteCard.podspec +22 -0
  4. package/android/build.gradle +79 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/config/command.json +205 -0
  8. package/android/src/main/cpp/CMakeLists.txt +19 -0
  9. package/android/src/main/cpp/validation.c +227 -0
  10. package/android/src/main/cpp/validation.h +19 -0
  11. package/android/src/main/java/com/onekeyfe/reactnativelitecard/LoggerManager.kt +35 -0
  12. package/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardModule.kt +420 -0
  13. package/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardPackage.kt +33 -0
  14. package/android/src/main/java/com/onekeyfe/reactnativelitecard/keys/KeysNativeProvider.kt +13 -0
  15. package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/Exceptions.kt +58 -0
  16. package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/NfcUtils.kt +142 -0
  17. package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/broadcast/NfcStatusChangeBroadcastReceiver.kt +56 -0
  18. package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/gpchannel/GPChannelNatives.kt +32 -0
  19. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/NfcConstant.kt +38 -0
  20. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/OnekeyLiteCard.kt +236 -0
  21. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/APDUParam.kt +17 -0
  22. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardInfo.java +84 -0
  23. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardResponse.java +37 -0
  24. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardState.kt +10 -0
  25. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/ParsedCertInfo.java +39 -0
  26. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SecureChanelParam.java +113 -0
  27. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SendResponse.kt +26 -0
  28. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/CommandGenerator.kt +178 -0
  29. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/Connection.kt +439 -0
  30. package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/GPCAPDUGenerator.kt +56 -0
  31. package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/EventUtils.kt +14 -0
  32. package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/GpsUtil.kt +38 -0
  33. package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/HexUtils.java +93 -0
  34. package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/LogUtil.kt +11 -0
  35. package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/MiUtil.kt +93 -0
  36. package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/NfcPermissionUtils.kt +24 -0
  37. package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/Utils.java +437 -0
  38. package/android/src/main/jniLibs/arm64-v8a/libgpchannelNDK.so +0 -0
  39. package/android/src/main/jniLibs/armeabi-v7a/libgpchannelNDK.so +0 -0
  40. package/ios/Classes/OKLiteCommand/OKLiteCommandModal.h +39 -0
  41. package/ios/Classes/OKLiteCommand/OKLiteCommandModal.m +143 -0
  42. package/ios/Classes/OKLiteCommand/OKLiteCommandTool.h +28 -0
  43. package/ios/Classes/OKLiteCommand/OKLiteCommandTool.m +53 -0
  44. package/ios/Classes/OKNFCBridge.h +28 -0
  45. package/ios/Classes/OKNFCBridge.mm +221 -0
  46. package/ios/Classes/OKNFCLiteDefine.h +108 -0
  47. package/ios/Classes/OKNFTLite/OKLiteProtocol.h +37 -0
  48. package/ios/Classes/OKNFTLite/OKLiteV1.h +41 -0
  49. package/ios/Classes/OKNFTLite/OKLiteV1.m +609 -0
  50. package/ios/Classes/OKNFTLite/OKLiteV2.h +17 -0
  51. package/ios/Classes/OKNFTLite/OKLiteV2.m +132 -0
  52. package/ios/Classes/OKNFTLite/OKNFCManager.h +40 -0
  53. package/ios/Classes/OKNFTLite/OKNFCManager.m +330 -0
  54. package/ios/Classes/Utils/NFCConfig.h +19 -0
  55. package/ios/Classes/Utils/NFCConfig.m +18 -0
  56. package/ios/Classes/Utils/NSData+OKNFCHexData.h +17 -0
  57. package/ios/Classes/Utils/NSData+OKNFCHexData.m +24 -0
  58. package/ios/Classes/Utils/NSData+StringToData.h +12 -0
  59. package/ios/Classes/Utils/NSData+StringToData.m +25 -0
  60. package/ios/Classes/Utils/NSString+OKAdd.h +14 -0
  61. package/ios/Classes/Utils/NSString+OKAdd.m +40 -0
  62. package/ios/Classes/Utils/NSString+OKNFCHexStr.h +18 -0
  63. package/ios/Classes/Utils/NSString+OKNFCHexStr.m +38 -0
  64. package/ios/Classes/Utils/OKNFCUtility.h +18 -0
  65. package/ios/Classes/Utils/OKNFCUtility.m +22 -0
  66. package/ios/Classes/Utils/OKTools.h +17 -0
  67. package/ios/Classes/Utils/OKTools.m +21 -0
  68. package/ios/GPChannelSDKCore.xcframework/Info.plist +52 -0
  69. package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/GPChannelSDKCore +0 -0
  70. package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Headers/GPChannelSDK.h +315 -0
  71. package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Headers/GPChannelSDKCore.h +19 -0
  72. package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Info.plist +0 -0
  73. package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Modules/module.modulemap +7 -0
  74. package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/_CodeSignature/CodeResources +147 -0
  75. package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/GPChannelSDKCore +0 -0
  76. package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Headers/GPChannelSDK.h +315 -0
  77. package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Headers/GPChannelSDKCore.h +19 -0
  78. package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Info.plist +0 -0
  79. package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Modules/module.modulemap +7 -0
  80. package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/_CodeSignature/CodeResources +147 -0
  81. package/ios/ReactNativeLiteCard.h +5 -0
  82. package/ios/ReactNativeLiteCard.mm +222 -0
  83. package/lib/module/NativeReactNativeLiteCard.js +25 -0
  84. package/lib/module/NativeReactNativeLiteCard.js.map +1 -0
  85. package/lib/module/index.js +71 -0
  86. package/lib/module/index.js.map +1 -0
  87. package/lib/module/package.json +1 -0
  88. package/lib/typescript/package.json +1 -0
  89. package/lib/typescript/src/NativeReactNativeLiteCard.d.ts +59 -0
  90. package/lib/typescript/src/NativeReactNativeLiteCard.d.ts.map +1 -0
  91. package/lib/typescript/src/index.d.ts +23 -0
  92. package/lib/typescript/src/index.d.ts.map +1 -0
  93. package/package.json +168 -0
  94. package/src/NativeReactNativeLiteCard.ts +112 -0
  95. package/src/index.tsx +94 -0
@@ -0,0 +1,38 @@
1
+ package so.onekey.app.wallet.lite.utils
2
+
3
+ import android.content.Context
4
+ import android.content.Intent
5
+ import android.provider.Settings
6
+
7
+
8
+ object GpsUtil {
9
+ /**
10
+ * 判断GPS是否开启,GPS或者AGPS开启一个就认为是开启的
11
+ * @param context
12
+ * @return true 表示开启
13
+ */
14
+ fun isOpen(context: Context?): Boolean {
15
+ if (context == null) {
16
+ return true
17
+ }
18
+ var locationMode = 0
19
+ val locationProviders: String
20
+
21
+ locationMode = try {
22
+ Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE)
23
+ } catch (e: Settings.SettingNotFoundException) {
24
+ e.printStackTrace()
25
+ return false
26
+ }
27
+ return locationMode != Settings.Secure.LOCATION_MODE_OFF
28
+ }
29
+
30
+ /**
31
+ * 跳转设置 打开GPS
32
+ * @param context
33
+ */
34
+ fun openGPS(context: Context) {
35
+ val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
36
+ context.startActivity(intent)
37
+ }
38
+ }
@@ -0,0 +1,93 @@
1
+ package so.onekey.app.wallet.lite.utils;
2
+
3
+ import java.math.BigInteger;
4
+ import java.util.Collections;
5
+
6
+ /**
7
+ * @author liyan
8
+ */
9
+ public class HexUtils {
10
+
11
+ public static byte[] hexString2Bytes(String hex) {
12
+ if (hex == null) return new byte[0];
13
+ return String2Bytes(hex, 16);
14
+ }
15
+
16
+ private static byte[] String2Bytes(String str, int digit) {
17
+ byte[] bArray = new BigInteger("10" + str, digit).toByteArray();
18
+
19
+ byte[] ret = new byte[bArray.length - 1];
20
+ for (int i = 0; i < ret.length; i++) {
21
+ ret[i] = bArray[i + 1];
22
+ }
23
+
24
+ return ret;
25
+ }
26
+
27
+
28
+ public static String stringToHexString(String s) {
29
+ if (s == null) return "";
30
+ String str = "";
31
+ for (int i = 0; i < s.length(); i++) {
32
+ int ch = s.charAt(i);
33
+ String s4 = Integer.toHexString(ch);
34
+ str = str + s4;
35
+ }
36
+ return str;
37
+ }
38
+
39
+ /**
40
+ * 将字节数组转换成十六进制的字符串
41
+ *
42
+ * @param bt 字节数组
43
+ * @param start 起始下标
44
+ * @param end 终止下标
45
+ */
46
+ public static String byteArr2HexStr(byte[] bt, int start, int end) {
47
+ return byteArr2HexStr(bt, start, end, "");
48
+ }
49
+
50
+ /**
51
+ * 将字节数组转换成十六进制的字符串
52
+ *
53
+ * @param bt 字节数组
54
+ */
55
+ public static String byteArr2HexStr(byte[] bt) {
56
+ if (bt == null) return "";
57
+ if (bt.length == 0) return "";
58
+ return byteArr2HexStr(bt, 0, bt.length, "");
59
+ }
60
+
61
+ /**
62
+ * 将字节数组转换成十六进制的字符串
63
+ *
64
+ * @param bt 字节数组
65
+ * @param start 起始下标
66
+ * @param end 终止下标
67
+ * @param sep 每个字节之间的分割字符串
68
+ */
69
+ public static String byteArr2HexStr(byte[] bt, int start, int end, String sep) {
70
+ if (bt == null || bt.length < end || start < 0 || start >= end) {
71
+ throw new RuntimeException("param format error");
72
+ }
73
+
74
+ StringBuffer sb = new StringBuffer();
75
+ for (int i = start; i < end; i++) {
76
+ sb.append(byte2HexStr(bt[i])).append(sep);
77
+ }
78
+ return sb.toString();
79
+ }
80
+
81
+ /**
82
+ * 将byte转换成对应的十六进制字符串(如:byte值0x3D转换成字符串"3D")
83
+ *
84
+ * @return 返回字符串长度一定为2
85
+ */
86
+ public static String byte2HexStr(byte b) {
87
+ int i = (b & 0xF0) >> 4;
88
+ int j = (b & 0x0F);
89
+ char c = (char) (i > 9 ? 'A' + i % 10 : '0' + i);
90
+ char d = (char) (j > 9 ? 'A' + j % 10 : '0' + j);
91
+ return "" + c + d;
92
+ }
93
+ }
@@ -0,0 +1,11 @@
1
+ package so.onekey.app.wallet.lite.utils
2
+
3
+ import so.onekey.app.wallet.lite.onekeyLite.NfcConstant
4
+ import so.onekey.app.wallet.lite.LoggerManager
5
+
6
+ object LogUtil {
7
+ @JvmStatic
8
+ fun printLog(tag: String, msg: String) {
9
+ if (NfcConstant.DEBUG) LoggerManager.getInstance()?.logInfo("$tag: $msg")
10
+ }
11
+ }
@@ -0,0 +1,93 @@
1
+ package so.onekey.app.wallet.lite.utils
2
+
3
+ import android.app.AppOpsManager
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.net.Uri
7
+ import android.os.Build
8
+ import android.provider.Settings
9
+ import android.util.Log
10
+ import androidx.annotation.IntDef
11
+ import androidx.annotation.RequiresApi
12
+ import so.onekey.app.wallet.lite.utils.MiUtil.PermissionResult.Companion.PERMISSION_ASK
13
+ import so.onekey.app.wallet.lite.utils.MiUtil.PermissionResult.Companion.PERMISSION_DENIED
14
+ import so.onekey.app.wallet.lite.utils.MiUtil.PermissionResult.Companion.PERMISSION_GRANTED
15
+ import so.onekey.app.wallet.lite.utils.MiUtil.PermissionResult.Companion.PERMISSION_UNKNOWN
16
+
17
+ object MiUtil {
18
+ val TAG = MiUtil::class.simpleName
19
+
20
+ @IntDef(value = [PERMISSION_GRANTED, PERMISSION_DENIED, PERMISSION_ASK, PERMISSION_UNKNOWN])
21
+ @kotlin.annotation.Retention(
22
+ AnnotationRetention.SOURCE
23
+ )
24
+ annotation class PermissionResult {
25
+ companion object {
26
+ /**
27
+ * Permission check result: this is returned by [.check]
28
+ * if the permission has been granted to the given package.
29
+ */
30
+ const val PERMISSION_GRANTED = 0
31
+
32
+ /**
33
+ * Permission check result: this is returned by [.check]
34
+ * if the permission has not been granted to the given package.
35
+ */
36
+ const val PERMISSION_DENIED = -1
37
+
38
+ const val PERMISSION_ASK = 1
39
+
40
+ const val PERMISSION_UNKNOWN = 2
41
+ }
42
+ }
43
+
44
+ /**
45
+ * 检测NFC权限是否有授权.
46
+ */
47
+ @PermissionResult
48
+ @RequiresApi(Build.VERSION_CODES.KITKAT)
49
+ fun checkNfcPermission(context: Context): Int {
50
+ try {
51
+ val mAppOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
52
+ val pkg = context.applicationContext.packageName
53
+ val uid = context.applicationInfo.uid
54
+ val appOpsClass = Class.forName(AppOpsManager::class.java.name)
55
+ val checkOpNoThrowMethod = appOpsClass.getDeclaredMethod(
56
+ "checkOpNoThrow", Integer.TYPE, Integer.TYPE,
57
+ String::class.java
58
+ )
59
+ //the ops of NFC is 10016,check /data/system/appops/xxx.xml
60
+ val invoke = checkOpNoThrowMethod.invoke(mAppOps, 10016, uid, pkg)
61
+ if (invoke == null) {
62
+ Log.d(TAG,
63
+ "MIUI check permission checkOpNoThrowMethod(AppOpsManager) invoke result is null"
64
+ )
65
+ return PERMISSION_UNKNOWN
66
+ }
67
+ val result = invoke.toString()
68
+ Log.d(TAG,
69
+ "MIUI check permission checkOpNoThrowMethod(AppOpsManager) invoke result = $result"
70
+ )
71
+ when (result) {
72
+ "0" -> return PERMISSION_GRANTED
73
+ "1" -> return PERMISSION_DENIED
74
+ "5" -> return PERMISSION_ASK
75
+ }
76
+ } catch (e: Exception) {
77
+ Log.d(TAG, "check nfc permission fail ${e.message}", e)
78
+ }
79
+ return PERMISSION_UNKNOWN
80
+ }
81
+
82
+ fun intentToAppSetting(context: Context): Boolean {
83
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
84
+ intent.data = Uri.fromParts("package", context.packageName, null)
85
+ return try {
86
+ context.startActivity(intent)
87
+ true
88
+ } catch (e: Exception) {
89
+ Log.d(TAG, "open app setting fail ${e.message}", e)
90
+ false
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,24 @@
1
+ package so.onekey.app.wallet.lite.utils
2
+
3
+ import android.app.Activity
4
+ import android.os.Build
5
+
6
+ object NfcPermissionUtils {
7
+
8
+ inline fun checkPermission(activity: Activity, doNext: () -> Unit): Int {
9
+ return if ("xiaomi".equals(Build.MANUFACTURER, true)) {
10
+ return checkMiuiPermission(activity, doNext)
11
+ } else {
12
+ doNext.invoke()
13
+ 0
14
+ }
15
+ }
16
+
17
+ inline fun checkMiuiPermission(activity: Activity, doNext: () -> Unit): Int {
18
+ when (MiUtil.checkNfcPermission(activity)) {
19
+ MiUtil.PermissionResult.PERMISSION_GRANTED -> doNext.invoke()
20
+ else -> {}
21
+ }
22
+ return MiUtil.checkNfcPermission(activity)
23
+ }
24
+ }
@@ -0,0 +1,437 @@
1
+ package so.onekey.app.wallet.lite.utils;
2
+
3
+ import android.annotation.SuppressLint;
4
+ import android.app.Activity;
5
+ import android.app.ActivityManager;
6
+ import android.app.Application;
7
+ import android.app.Application.ActivityLifecycleCallbacks;
8
+ import android.content.Context;
9
+ import android.os.Bundle;
10
+
11
+ import androidx.annotation.NonNull;
12
+ import androidx.annotation.Nullable;
13
+
14
+ import com.facebook.react.bridge.ReactApplicationContext;
15
+
16
+ import org.jetbrains.annotations.NotNull;
17
+
18
+ import java.lang.reflect.Field;
19
+ import java.lang.reflect.InvocationTargetException;
20
+ import java.util.HashMap;
21
+ import java.util.LinkedList;
22
+ import java.util.List;
23
+ import java.util.Map;
24
+ import java.util.regex.Matcher;
25
+ import java.util.regex.Pattern;
26
+
27
+ /**
28
+ * <pre>
29
+ * author:
30
+ * ___ ___ ___ ___
31
+ * _____ / /\ /__/\ /__/| / /\
32
+ * / /::\ / /::\ \ \:\ | |:| / /:/
33
+ * / /:/\:\ ___ ___ / /:/\:\ \ \:\ | |:| /__/::\
34
+ * / /:/~/::\ /__/\ / /\ / /:/~/::\ _____\__\:\ __| |:| \__\/\:\
35
+ * /__/:/ /:/\:| \ \:\ / /:/ /__/:/ /:/\:\ /__/::::::::\ /__/\_|:|____ \ \:\
36
+ * \ \:\/:/~/:/ \ \:\ /:/ \ \:\/:/__\/ \ \:\~~\~~\/ \ \:\/:::::/ \__\:\
37
+ * \ \::/ /:/ \ \:\/:/ \ \::/ \ \:\ ~~~ \ \::/~~~~ / /:/
38
+ * \ \:\/:/ \ \::/ \ \:\ \ \:\ \ \:\ /__/:/
39
+ * \ \::/ \__\/ \ \:\ \ \:\ \ \:\ \__\/
40
+ * \__\/ \__\/ \__\/ \__\/
41
+ * blog : http://blankj.com
42
+ * time : 16/12/08
43
+ * desc : utils about initialization
44
+ * </pre>
45
+ */
46
+ public final class Utils {
47
+
48
+ @SuppressLint("StaticFieldLeak")
49
+ private static Application sApplication;
50
+
51
+ static final ActivityLifecycleImpl ACTIVITY_LIFECYCLE = new ActivityLifecycleImpl();
52
+
53
+ private Utils() {
54
+ throw new UnsupportedOperationException("u can't instantiate me...");
55
+ }
56
+
57
+ /**
58
+ * Init utils.
59
+ *
60
+ * <p>Init it in the class of Application.
61
+ *
62
+ * @param context context
63
+ */
64
+ public static void init(@NonNull final ReactApplicationContext context) {
65
+ Utils.getActivityLifecycle().setTopActivity(context.getCurrentActivity());
66
+ init((Application) context.getApplicationContext());
67
+ }
68
+
69
+ /**
70
+ * Init utils.
71
+ *
72
+ * <p>Init it in the class of Application.
73
+ *
74
+ * @param app application
75
+ */
76
+ public static void init(@NonNull final Application app) {
77
+ if (sApplication == null) {
78
+ Utils.sApplication = app;
79
+ Utils.sApplication.registerActivityLifecycleCallbacks(ACTIVITY_LIFECYCLE);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Return the context of Application object.
85
+ *
86
+ * @return the context of Application object
87
+ */
88
+ public static Application getApp() {
89
+ if (sApplication != null) {
90
+ return sApplication;
91
+ }
92
+ try {
93
+ @SuppressLint("PrivateApi")
94
+ Class<?> activityThread = Class.forName("android.app.ActivityThread");
95
+ Object at = activityThread.getMethod("currentActivityThread").invoke(null);
96
+ Object app = activityThread.getMethod("getApplication").invoke(at);
97
+ if (app == null) {
98
+ throw new NullPointerException("u should init first");
99
+ }
100
+ init((Application) app);
101
+ return sApplication;
102
+ } catch (NoSuchMethodException e) {
103
+ e.printStackTrace();
104
+ } catch (IllegalAccessException e) {
105
+ e.printStackTrace();
106
+ } catch (InvocationTargetException e) {
107
+ e.printStackTrace();
108
+ } catch (ClassNotFoundException e) {
109
+ e.printStackTrace();
110
+ }
111
+ throw new NullPointerException("u should init first");
112
+ }
113
+
114
+ public static ActivityLifecycleImpl getActivityLifecycle() {
115
+ return ACTIVITY_LIFECYCLE;
116
+ }
117
+
118
+ public static LinkedList<Activity> getActivityList() {
119
+ return ACTIVITY_LIFECYCLE.mActivityList;
120
+ }
121
+
122
+ @NotNull
123
+ public static Context getTopActivityOrApp() {
124
+ if (isAppForeground()) {
125
+ Activity topActivity = ACTIVITY_LIFECYCLE.getTopActivity();
126
+ return topActivity == null ? Utils.getApp() : topActivity;
127
+ } else {
128
+ return Utils.getApp();
129
+ }
130
+ }
131
+
132
+ @Nullable
133
+ public static Activity getTopActivity() {
134
+ if (!isAppForeground()) {
135
+ return null;
136
+ }
137
+ return ACTIVITY_LIFECYCLE.getTopActivity();
138
+ }
139
+
140
+ /**
141
+ * Finish all of activities.
142
+ */
143
+ public static void finishAllActivities() {
144
+ finishAllActivities(false);
145
+ }
146
+
147
+ /**
148
+ * Finish all of activities.
149
+ *
150
+ * @param isLoadAnim True to use animation for the outgoing activity, false otherwise.
151
+ */
152
+ public static void finishAllActivities(final boolean isLoadAnim) {
153
+ List<Activity> activityList = getActivityList();
154
+ for (Activity act : activityList) {
155
+ // sActivityList remove the index activity at onActivityDestroyed
156
+ act.finish();
157
+ if (!isLoadAnim) {
158
+ act.overridePendingTransition(0, 0);
159
+ }
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Finish all of activities except the newest activity.
165
+ */
166
+ public static void finishAllActivitiesExceptNewest() {
167
+ finishAllActivitiesExceptNewest(false);
168
+ }
169
+
170
+ /**
171
+ * Finish all of activities except the newest activity.
172
+ *
173
+ * @param isLoadAnim True to use animation for the outgoing activity, false otherwise.
174
+ */
175
+ public static void finishAllActivitiesExceptNewest(final boolean isLoadAnim) {
176
+ List<Activity> activities = getActivityList();
177
+ for (int i = 1; i < activities.size(); i++) {
178
+ finishActivity(activities.get(i), isLoadAnim);
179
+ }
180
+ }
181
+
182
+ public static void finishActivity(@NonNull final Activity activity) {
183
+ finishActivity(activity, false);
184
+ }
185
+
186
+ public static void finishActivity(@NonNull final Activity activity, final boolean isLoadAnim) {
187
+ activity.finish();
188
+ if (!isLoadAnim) {
189
+ activity.overridePendingTransition(0, 0);
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Finish the activity.
195
+ *
196
+ * @param clz The activity class.
197
+ */
198
+ public static void finishActivity(@NonNull final Class<? extends Activity> clz) {
199
+ finishActivity(clz, false);
200
+ }
201
+
202
+ /**
203
+ * Finish the activity.
204
+ *
205
+ * @param clz The activity class.
206
+ * @param isLoadAnim True to use animation for the outgoing activity, false otherwise.
207
+ */
208
+ public static void finishActivity(
209
+ @NonNull final Class<? extends Activity> clz, final boolean isLoadAnim) {
210
+ List<Activity> activities = getActivityList();
211
+ for (Activity activity : activities) {
212
+ if (activity.getClass().equals(clz)) {
213
+ activity.finish();
214
+ if (!isLoadAnim) {
215
+ activity.overridePendingTransition(0, 0);
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Finish the activities whose type not equals the activity class.
223
+ *
224
+ * @param clz The activity class.
225
+ */
226
+ public static void finishOtherActivities(@NonNull final Class<? extends Activity> clz) {
227
+ finishOtherActivities(clz, false);
228
+ }
229
+
230
+ /**
231
+ * Finish the activities whose type not equals the activity class.
232
+ *
233
+ * @param clz The activity class.
234
+ * @param isLoadAnim True to use animation for the outgoing activity, false otherwise.
235
+ */
236
+ public static void finishOtherActivities(
237
+ @NonNull final Class<? extends Activity> clz, final boolean isLoadAnim) {
238
+ List<Activity> activities = getActivityList();
239
+ for (Activity act : activities) {
240
+ if (!act.getClass().equals(clz)) {
241
+ finishActivity(act, isLoadAnim);
242
+ }
243
+ }
244
+ }
245
+
246
+ public static boolean isAppForeground() {
247
+ ActivityManager am =
248
+ (ActivityManager) Utils.getApp().getSystemService(Context.ACTIVITY_SERVICE);
249
+ if (am == null) {
250
+ return false;
251
+ }
252
+ List<ActivityManager.RunningAppProcessInfo> info = am.getRunningAppProcesses();
253
+ if (info == null || info.size() == 0) {
254
+ return false;
255
+ }
256
+ for (ActivityManager.RunningAppProcessInfo aInfo : info) {
257
+ if (aInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
258
+ return aInfo.processName.equals(Utils.getApp().getPackageName());
259
+ }
260
+ }
261
+ return false;
262
+ }
263
+
264
+ static class ActivityLifecycleImpl implements ActivityLifecycleCallbacks {
265
+
266
+ final LinkedList<Activity> mActivityList = new LinkedList<>();
267
+ final HashMap<Object, OnAppStatusChangedListener> mStatusListenerMap = new HashMap<>();
268
+
269
+ private int mForegroundCount = 0;
270
+ private int mConfigCount = 0;
271
+
272
+ void addListener(final Object object, final OnAppStatusChangedListener listener) {
273
+ mStatusListenerMap.put(object, listener);
274
+ }
275
+
276
+ void removeListener(final Object object) {
277
+ mStatusListenerMap.remove(object);
278
+ }
279
+
280
+ @Override
281
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
282
+ setTopActivity(activity);
283
+ }
284
+
285
+ @Override
286
+ public void onActivityStarted(Activity activity) {
287
+ setTopActivity(activity);
288
+ if (mForegroundCount <= 0) {
289
+ postStatus(true);
290
+ }
291
+ if (mConfigCount < 0) {
292
+ ++mConfigCount;
293
+ } else {
294
+ ++mForegroundCount;
295
+ }
296
+ }
297
+
298
+ @Override
299
+ public void onActivityResumed(Activity activity) {
300
+ setTopActivity(activity);
301
+ }
302
+
303
+ @Override
304
+ public void onActivityPaused(Activity activity) {
305
+ /**/
306
+ }
307
+
308
+ @Override
309
+ public void onActivityStopped(Activity activity) {
310
+ if (activity.isChangingConfigurations()) {
311
+ --mConfigCount;
312
+ } else {
313
+ --mForegroundCount;
314
+ if (mForegroundCount <= 0) {
315
+ postStatus(false);
316
+ }
317
+ }
318
+ }
319
+
320
+ @Override
321
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
322
+ /**/
323
+ }
324
+
325
+ @Override
326
+ public void onActivityDestroyed(Activity activity) {
327
+ mActivityList.remove(activity);
328
+ }
329
+
330
+ private void postStatus(final boolean isForeground) {
331
+ if (mStatusListenerMap.isEmpty()) {
332
+ return;
333
+ }
334
+ for (OnAppStatusChangedListener onAppStatusChangedListener :
335
+ mStatusListenerMap.values()) {
336
+ if (onAppStatusChangedListener == null) {
337
+ return;
338
+ }
339
+ if (isForeground) {
340
+ onAppStatusChangedListener.onForeground();
341
+ } else {
342
+ onAppStatusChangedListener.onBackground();
343
+ }
344
+ }
345
+ }
346
+
347
+ private void setTopActivity(final Activity activity) {
348
+ if (activity == null || mActivityList == null) {
349
+ return;
350
+ }
351
+ if (mActivityList.contains(activity)) {
352
+ Activity lastActivity = mActivityList.getLast();
353
+ if (lastActivity != null && !lastActivity.equals(activity)) {
354
+ mActivityList.remove(activity);
355
+ mActivityList.addLast(activity);
356
+ }
357
+ } else {
358
+ mActivityList.addLast(activity);
359
+ }
360
+ }
361
+
362
+ @Nullable
363
+ Activity getTopActivity() {
364
+ if (!mActivityList.isEmpty()) {
365
+ final Activity topActivity = mActivityList.getLast();
366
+ if (topActivity != null) {
367
+ return topActivity;
368
+ }
369
+ }
370
+ // using reflect to get top activity
371
+ try {
372
+ @SuppressLint("PrivateApi")
373
+ Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
374
+ Object activityThread =
375
+ activityThreadClass.getMethod("currentActivityThread").invoke(null);
376
+ Field activitiesField = activityThreadClass.getDeclaredField("mActivityList");
377
+ activitiesField.setAccessible(true);
378
+ Map activities = (Map) activitiesField.get(activityThread);
379
+ if (activities == null) {
380
+ return null;
381
+ }
382
+ for (Object activityRecord : activities.values()) {
383
+ Class activityRecordClass = activityRecord.getClass();
384
+ Field pausedField = activityRecordClass.getDeclaredField("paused");
385
+ pausedField.setAccessible(true);
386
+ if (!pausedField.getBoolean(activityRecord)) {
387
+ Field activityField = activityRecordClass.getDeclaredField("activity");
388
+ activityField.setAccessible(true);
389
+ Activity activity = (Activity) activityField.get(activityRecord);
390
+ setTopActivity(activity);
391
+ return activity;
392
+ }
393
+ }
394
+ } catch (ClassNotFoundException e) {
395
+ e.printStackTrace();
396
+ } catch (IllegalAccessException e) {
397
+ e.printStackTrace();
398
+ } catch (InvocationTargetException e) {
399
+ e.printStackTrace();
400
+ } catch (NoSuchMethodException e) {
401
+ e.printStackTrace();
402
+ } catch (NoSuchFieldException e) {
403
+ e.printStackTrace();
404
+ }
405
+ return null;
406
+ }
407
+ }
408
+
409
+ ///////////////////////////////////////////////////////////////////////////
410
+ // interface
411
+ ///////////////////////////////////////////////////////////////////////////
412
+
413
+ public interface OnAppStatusChangedListener {
414
+
415
+ void onForeground();
416
+
417
+ void onBackground();
418
+ }
419
+
420
+ public static int dp2px(final @NotNull Context context, final Float dpValue) {
421
+ final float scale = context.getResources().getDisplayMetrics().density;
422
+ return (int) (dpValue * scale + 0.5f);
423
+ }
424
+
425
+ public static int sp2px(final @NotNull Context context, final Float sp) {
426
+ final float scale = context.getResources().getDisplayMetrics().scaledDensity;
427
+ return (int) (sp * scale + 0.5f);
428
+ }
429
+
430
+ public static boolean isEmail(String email) {
431
+ if (null == email || "".equals(email)) return false;
432
+ // Pattern p = Pattern.compile("\\w+@(\\w+.)+[a-z]{2,3}"); //简单匹配
433
+ Pattern p = Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"); // 复杂匹配
434
+ Matcher m = p.matcher(email);
435
+ return m.matches();
436
+ }
437
+ }