diff --git a/app/src/androidTest/java/com/smsreceive/app/SmsProviderInstrumentedTest.java b/app/src/androidTest/java/com/smsreceive/app/sms/SmsProviderInstrumentedTest.java
similarity index 95%
rename from app/src/androidTest/java/com/smsreceive/app/SmsProviderInstrumentedTest.java
rename to app/src/androidTest/java/com/smsreceive/app/sms/SmsProviderInstrumentedTest.java
index 0d9761d..b460c18 100644
--- a/app/src/androidTest/java/com/smsreceive/app/SmsProviderInstrumentedTest.java
+++ b/app/src/androidTest/java/com/smsreceive/app/sms/SmsProviderInstrumentedTest.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.sms;
import android.content.Context;
import android.util.Log;
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c3a4ad5..1300a6f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,7 +15,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
@@ -25,7 +25,7 @@
@@ -35,7 +35,7 @@
@@ -46,12 +46,12 @@
diff --git a/app/src/main/java/com/smsreceive/app/FeishuWebhookPushResult.java b/app/src/main/java/com/smsreceive/app/FeishuWebhookPushResult.java
deleted file mode 100644
index 0d66fdf..0000000
--- a/app/src/main/java/com/smsreceive/app/FeishuWebhookPushResult.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.smsreceive.app;
-
-final class FeishuWebhookPushResult {
- static final String STATUS_SUCCESS = "success";
- static final String STATUS_DISABLED = "disabled";
- static final String STATUS_MISSING_CONFIG = "missing_config";
- static final String STATUS_SIGN_ERROR = "sign_error";
- static final String STATUS_NETWORK_ERROR = "network_error";
- static final String STATUS_TIMEOUT = "timeout";
- static final String STATUS_HTTP_ERROR = "http_error";
- static final String STATUS_INVALID_JSON = "invalid_json";
- static final String STATUS_API_ERROR = "api_error";
-
- final boolean success;
- final String status;
- final String message;
- final int httpStatus;
- final int apiCode;
- final long timeMillis;
-
- private FeishuWebhookPushResult(
- boolean success,
- String status,
- String message,
- int httpStatus,
- int apiCode,
- long timeMillis) {
- this.success = success;
- this.status = status == null ? "" : status;
- this.message = message == null ? "" : message;
- this.httpStatus = httpStatus;
- this.apiCode = apiCode;
- this.timeMillis = timeMillis;
- }
-
- static FeishuWebhookPushResult success(String message) {
- return new FeishuWebhookPushResult(true, STATUS_SUCCESS, message, 200, 0, System.currentTimeMillis());
- }
-
- static FeishuWebhookPushResult failure(String status, String message) {
- return failure(status, message, 0, 0);
- }
-
- static FeishuWebhookPushResult failure(String status, String message, int httpStatus, int apiCode) {
- return new FeishuWebhookPushResult(false, status, message, httpStatus, apiCode, System.currentTimeMillis());
- }
-}
diff --git a/app/src/main/java/com/smsreceive/app/FeishuWebhookClient.java b/app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookClient.java
similarity index 93%
rename from app/src/main/java/com/smsreceive/app/FeishuWebhookClient.java
rename to app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookClient.java
index ab29327..7282305 100644
--- a/app/src/main/java/com/smsreceive/app/FeishuWebhookClient.java
+++ b/app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookClient.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.feishu;
import android.content.Context;
import android.content.Intent;
@@ -11,6 +11,8 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import com.smsreceive.app.sms.CaptureResult;
+
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
@@ -29,7 +31,7 @@ import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
-final class FeishuWebhookClient {
+public final class FeishuWebhookClient {
private static final String TAG = "[SMS]SmsReceive";
private static final String WEBHOOK_URL_PREFIX = "https://open.feishu.cn/open-apis/bot/v2/hook/";
private static final char[] BASE64_TABLE =
@@ -47,7 +49,7 @@ final class FeishuWebhookClient {
private FeishuWebhookClient() {
}
- static void pushCaptureResultAsync(Context context, CaptureResult result) {
+ public static void pushCaptureResultAsync(Context context, CaptureResult result) {
if (context == null || result == null) {
return;
}
@@ -76,7 +78,7 @@ final class FeishuWebhookClient {
pushMarkdownAsync(appContext, markdown, result);
}
- static void pushMarkdownAsync(Context context, String markdownContent) {
+ public static void pushMarkdownAsync(Context context, String markdownContent) {
pushMarkdownAsync(context, markdownContent, null);
}
@@ -98,7 +100,7 @@ final class FeishuWebhookClient {
});
}
- static FeishuWebhookPushResult pushMarkdown(
+ public static FeishuWebhookPushResult pushMarkdown(
FeishuWebhookConfigStore.Config config,
String markdownContent,
long timestampSeconds) {
@@ -157,14 +159,14 @@ final class FeishuWebhookClient {
}
}
- static String generateSign(String secret, long timestampSeconds) throws GeneralSecurityException {
+ public static String generateSign(String secret, long timestampSeconds) throws GeneralSecurityException {
String stringToSign = timestampSeconds + "\n" + (secret == null ? "" : secret);
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
return base64EncodeNoWrap(mac.doFinal(new byte[0]));
}
- static String buildRequestJson(String markdownContent, long timestampSeconds, String sign) throws JSONException {
+ public static String buildRequestJson(String markdownContent, long timestampSeconds, String sign) throws JSONException {
JSONObject markdown = new JSONObject()
.put("tag", "markdown")
.put("content", markdownContent == null ? "" : markdownContent);
@@ -178,7 +180,7 @@ final class FeishuWebhookClient {
.toString();
}
- static FeishuWebhookPushResult parseResponse(String responseBody) {
+ public static FeishuWebhookPushResult parseResponse(String responseBody) {
try {
JSONObject json = new JSONObject(responseBody == null ? "" : responseBody);
int code = json.optInt("code", Integer.MIN_VALUE);
@@ -198,15 +200,15 @@ final class FeishuWebhookClient {
}
}
- static String buildWebhookUrl(String webhookId) {
+ public static String buildWebhookUrl(String webhookId) {
return WEBHOOK_URL_PREFIX + (webhookId == null ? "" : webhookId.trim());
}
- static String buildMarkdownFromCapture(CaptureResult result) {
+ public static String buildMarkdownFromCapture(CaptureResult result) {
return buildMarkdownFromCapture(result, new FeishuWebhookConfigStore.Config(false, "", "", false, false));
}
- static String buildMarkdownFromCapture(CaptureResult result, FeishuWebhookConfigStore.Config config) {
+ public static String buildMarkdownFromCapture(CaptureResult result, FeishuWebhookConfigStore.Config config) {
boolean filterCode = config != null && config.filterVerificationCode;
boolean includeFullBody = config == null || !filterCode || config.sendFullBodyDebug;
StringBuilder builder = new StringBuilder();
diff --git a/app/src/main/java/com/smsreceive/app/FeishuWebhookConfigStore.java b/app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookConfigStore.java
similarity index 89%
rename from app/src/main/java/com/smsreceive/app/FeishuWebhookConfigStore.java
rename to app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookConfigStore.java
index 2774e1f..fc1975d 100644
--- a/app/src/main/java/com/smsreceive/app/FeishuWebhookConfigStore.java
+++ b/app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookConfigStore.java
@@ -1,9 +1,11 @@
-package com.smsreceive.app;
+package com.smsreceive.app.feishu;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
+import com.smsreceive.app.sms.CaptureResult;
+
import org.json.JSONException;
import org.json.JSONObject;
@@ -16,8 +18,8 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
-final class FeishuWebhookConfigStore {
- static final String ACTION_PUSH_UPDATED = "com.smsreceive.app.ACTION_FEISHU_PUSH_UPDATED";
+public final class FeishuWebhookConfigStore {
+ public static final String ACTION_PUSH_UPDATED = "com.smsreceive.app.ACTION_FEISHU_PUSH_UPDATED";
private static final String TAG = "[SMS]SmsReceive";
private static final String PREFS = "feishu_webhook";
@@ -43,7 +45,7 @@ final class FeishuWebhookConfigStore {
private FeishuWebhookConfigStore() {
}
- static Config loadConfig(Context context) {
+ public static Config loadConfig(Context context) {
ensureDefaultConfigFile(context);
File file = configFile(context);
if (!file.exists()) {
@@ -59,7 +61,7 @@ final class FeishuWebhookConfigStore {
}
}
- static void saveConfig(
+ public static void saveConfig(
Context context,
boolean enabled,
String webhookId,
@@ -82,7 +84,7 @@ final class FeishuWebhookConfigStore {
}
}
- static void saveLastResult(Context context, FeishuWebhookPushResult result) {
+ public static void saveLastResult(Context context, FeishuWebhookPushResult result) {
preferences(context).edit()
.putLong(KEY_LAST_TIME, result.timeMillis)
.putBoolean(KEY_LAST_SUCCESS, result.success)
@@ -136,7 +138,7 @@ final class FeishuWebhookConfigStore {
+ ", smsKey=" + smsKey);
}
- static LastResult loadLastResult(Context context) {
+ public static LastResult loadLastResult(Context context) {
SharedPreferences prefs = preferences(context);
return new LastResult(
prefs.getLong(KEY_LAST_TIME, 0L),
@@ -147,14 +149,14 @@ final class FeishuWebhookConfigStore {
prefs.getInt(KEY_LAST_API_CODE, 0));
}
- static LastPushedSms loadLastPushedSms(Context context) {
+ public static LastPushedSms loadLastPushedSms(Context context) {
SharedPreferences prefs = preferences(context);
return new LastPushedSms(
prefs.getLong(KEY_LAST_PUSHED_SMS_RECEIVED_SECOND, 0L),
prefs.getString(KEY_LAST_PUSHED_SMS_KEY, ""));
}
- static String maskSecret(String secret) {
+ public static String maskSecret(String secret) {
if (isEmpty(secret)) {
return "";
}
@@ -164,15 +166,15 @@ final class FeishuWebhookConfigStore {
return secret.substring(0, 3) + "***" + secret.substring(secret.length() - 3);
}
- static String configPath(Context context) {
+ public static String configPath(Context context) {
return configFile(context).getAbsolutePath();
}
- static String defaultConfigPath(Context context) {
+ public static String defaultConfigPath(Context context) {
return defaultConfigFile(context).getAbsolutePath();
}
- static String configTemplate() {
+ public static String configTemplate() {
try {
return configToJson(defaultConfig()).toString(2);
} catch (JSONException e) {
@@ -289,14 +291,14 @@ final class FeishuWebhookConfigStore {
+ Integer.toHexString((result.body == null ? "" : result.body).hashCode());
}
- static final class Config {
- final boolean enabled;
- final String webhookId;
- final String secret;
- final boolean sendFullBodyDebug;
- final boolean filterVerificationCode;
+ public static final class Config {
+ public final boolean enabled;
+ public final String webhookId;
+ public final String secret;
+ public final boolean sendFullBodyDebug;
+ public final boolean filterVerificationCode;
- Config(
+ public Config(
boolean enabled,
String webhookId,
String secret,
@@ -309,22 +311,22 @@ final class FeishuWebhookConfigStore {
this.filterVerificationCode = filterVerificationCode;
}
- boolean hasWebhookId() {
+ public boolean hasWebhookId() {
return !isEmpty(webhookId);
}
- boolean hasSecret() {
+ public boolean hasSecret() {
return !isEmpty(secret);
}
}
- static final class LastResult {
- final long timeMillis;
- final boolean success;
- final String status;
- final String message;
- final int httpStatus;
- final int apiCode;
+ public static final class LastResult {
+ public final long timeMillis;
+ public final boolean success;
+ public final String status;
+ public final String message;
+ public final int httpStatus;
+ public final int apiCode;
LastResult(long timeMillis, boolean success, String status, String message, int httpStatus, int apiCode) {
this.timeMillis = timeMillis;
@@ -336,9 +338,9 @@ final class FeishuWebhookConfigStore {
}
}
- static final class LastPushedSms {
- final long receivedSecond;
- final String smsKey;
+ public static final class LastPushedSms {
+ public final long receivedSecond;
+ public final String smsKey;
LastPushedSms(long receivedSecond, String smsKey) {
this.receivedSecond = receivedSecond;
diff --git a/app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookPushResult.java b/app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookPushResult.java
new file mode 100644
index 0000000..232685a
--- /dev/null
+++ b/app/src/main/java/com/smsreceive/app/feishu/FeishuWebhookPushResult.java
@@ -0,0 +1,47 @@
+package com.smsreceive.app.feishu;
+
+public final class FeishuWebhookPushResult {
+ public static final String STATUS_SUCCESS = "success";
+ public static final String STATUS_DISABLED = "disabled";
+ public static final String STATUS_MISSING_CONFIG = "missing_config";
+ public static final String STATUS_SIGN_ERROR = "sign_error";
+ public static final String STATUS_NETWORK_ERROR = "network_error";
+ public static final String STATUS_TIMEOUT = "timeout";
+ public static final String STATUS_HTTP_ERROR = "http_error";
+ public static final String STATUS_INVALID_JSON = "invalid_json";
+ public static final String STATUS_API_ERROR = "api_error";
+
+ public final boolean success;
+ public final String status;
+ public final String message;
+ public final int httpStatus;
+ public final int apiCode;
+ public final long timeMillis;
+
+ private FeishuWebhookPushResult(
+ boolean success,
+ String status,
+ String message,
+ int httpStatus,
+ int apiCode,
+ long timeMillis) {
+ this.success = success;
+ this.status = status == null ? "" : status;
+ this.message = message == null ? "" : message;
+ this.httpStatus = httpStatus;
+ this.apiCode = apiCode;
+ this.timeMillis = timeMillis;
+ }
+
+ public static FeishuWebhookPushResult success(String message) {
+ return new FeishuWebhookPushResult(true, STATUS_SUCCESS, message, 200, 0, System.currentTimeMillis());
+ }
+
+ public static FeishuWebhookPushResult failure(String status, String message) {
+ return failure(status, message, 0, 0);
+ }
+
+ public static FeishuWebhookPushResult failure(String status, String message, int httpStatus, int apiCode) {
+ return new FeishuWebhookPushResult(false, status, message, httpStatus, apiCode, System.currentTimeMillis());
+ }
+}
diff --git a/app/src/main/java/com/smsreceive/app/BootReceiver.java b/app/src/main/java/com/smsreceive/app/keepalive/BootReceiver.java
similarity index 98%
rename from app/src/main/java/com/smsreceive/app/BootReceiver.java
rename to app/src/main/java/com/smsreceive/app/keepalive/BootReceiver.java
index 39108b7..db9d459 100644
--- a/app/src/main/java/com/smsreceive/app/BootReceiver.java
+++ b/app/src/main/java/com/smsreceive/app/keepalive/BootReceiver.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.keepalive;
import android.content.BroadcastReceiver;
import android.content.Context;
diff --git a/app/src/main/java/com/smsreceive/app/KeepAliveDatabase.java b/app/src/main/java/com/smsreceive/app/keepalive/KeepAliveDatabase.java
similarity index 94%
rename from app/src/main/java/com/smsreceive/app/KeepAliveDatabase.java
rename to app/src/main/java/com/smsreceive/app/keepalive/KeepAliveDatabase.java
index d4fab6e..3ed49a2 100644
--- a/app/src/main/java/com/smsreceive/app/KeepAliveDatabase.java
+++ b/app/src/main/java/com/smsreceive/app/keepalive/KeepAliveDatabase.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.keepalive;
import android.content.ContentValues;
import android.content.Context;
@@ -11,7 +11,7 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
-final class KeepAliveDatabase {
+public final class KeepAliveDatabase {
private static final String TAG = "[SMS]SmsReceive";
private static final String DATABASE_NAME = "sms_keep_alive.db";
private static final int DATABASE_VERSION = 1;
@@ -23,7 +23,7 @@ final class KeepAliveDatabase {
private KeepAliveDatabase() {
}
- static long writeLastActiveTime(Context context) {
+ public static long writeLastActiveTime(Context context) {
long now = System.currentTimeMillis();
SQLiteDatabase database = helper(context).getWritableDatabase();
ContentValues values = new ContentValues();
@@ -35,7 +35,7 @@ final class KeepAliveDatabase {
return now;
}
- static long readLastActiveTime(Context context) {
+ public static long readLastActiveTime(Context context) {
SQLiteDatabase database = helper(context).getReadableDatabase();
try (Cursor cursor = database.query(
TABLE_META,
diff --git a/app/src/main/java/com/smsreceive/app/KeepAliveNotification.java b/app/src/main/java/com/smsreceive/app/keepalive/KeepAliveNotification.java
similarity index 96%
rename from app/src/main/java/com/smsreceive/app/KeepAliveNotification.java
rename to app/src/main/java/com/smsreceive/app/keepalive/KeepAliveNotification.java
index 4d44b08..7e5dedd 100644
--- a/app/src/main/java/com/smsreceive/app/KeepAliveNotification.java
+++ b/app/src/main/java/com/smsreceive/app/keepalive/KeepAliveNotification.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.keepalive;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -9,6 +9,8 @@ import android.content.Intent;
import android.os.Build;
import android.util.Log;
+import com.smsreceive.app.ui.MainActivity;
+
final class KeepAliveNotification {
static final int NOTIFICATION_ID = 2101;
private static final String TAG = "[SMS]SmsReceive";
diff --git a/app/src/main/java/com/smsreceive/app/KeepAliveStateStore.java b/app/src/main/java/com/smsreceive/app/keepalive/KeepAliveStateStore.java
similarity index 79%
rename from app/src/main/java/com/smsreceive/app/KeepAliveStateStore.java
rename to app/src/main/java/com/smsreceive/app/keepalive/KeepAliveStateStore.java
index a1d75c0..74de526 100644
--- a/app/src/main/java/com/smsreceive/app/KeepAliveStateStore.java
+++ b/app/src/main/java/com/smsreceive/app/keepalive/KeepAliveStateStore.java
@@ -1,11 +1,11 @@
-package com.smsreceive.app;
+package com.smsreceive.app.keepalive;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log;
-final class KeepAliveStateStore {
+public final class KeepAliveStateStore {
private static final String TAG = "[SMS]SmsReceive";
private static final String PREFS = "sms_keep_alive";
@@ -23,14 +23,14 @@ final class KeepAliveStateStore {
private KeepAliveStateStore() {
}
- static void setEnabledByUser(Context context, boolean enabled) {
+ public static void setEnabledByUser(Context context, boolean enabled) {
Log.d(TAG, "KeepAliveStateStore.setEnabledByUser enabled=" + enabled);
preferences(context).edit()
.putBoolean(KEY_ENABLED_BY_USER, enabled)
.apply();
}
- static void recordServiceStarted(Context context) {
+ public static void recordServiceStarted(Context context) {
long now = System.currentTimeMillis();
Log.d(TAG, "KeepAliveStateStore.recordServiceStarted time=" + now);
preferences(context).edit()
@@ -40,7 +40,7 @@ final class KeepAliveStateStore {
.apply();
}
- static void recordServiceStopped(Context context, String reason) {
+ public static void recordServiceStopped(Context context, String reason) {
Log.d(TAG, "KeepAliveStateStore.recordServiceStopped reason=" + reason);
preferences(context).edit()
.putBoolean(KEY_SERVICE_RUNNING, false)
@@ -48,7 +48,7 @@ final class KeepAliveStateStore {
.apply();
}
- static void recordHeartbeat(Context context) {
+ public static void recordHeartbeat(Context context) {
Log.d(TAG, "KeepAliveStateStore.recordHeartbeat");
preferences(context).edit()
.putBoolean(KEY_SERVICE_RUNNING, true)
@@ -56,7 +56,7 @@ final class KeepAliveStateStore {
.apply();
}
- static void recordBootEvent(Context context, String action) {
+ public static void recordBootEvent(Context context, String action) {
long now = System.currentTimeMillis();
Log.d(TAG, "KeepAliveStateStore.recordBootEvent action=" + action + ", time=" + now);
preferences(context).edit()
@@ -65,7 +65,7 @@ final class KeepAliveStateStore {
.apply();
}
- static void recordServiceStartFailure(Context context, String reason) {
+ public static void recordServiceStartFailure(Context context, String reason) {
Log.w(TAG, "KeepAliveStateStore.recordServiceStartFailure reason=" + reason);
preferences(context).edit()
.putBoolean(KEY_SERVICE_RUNNING, false)
@@ -73,39 +73,39 @@ final class KeepAliveStateStore {
.apply();
}
- static void setManualAutostartConfirmed(Context context, boolean confirmed) {
+ public static void setManualAutostartConfirmed(Context context, boolean confirmed) {
Log.d(TAG, "KeepAliveStateStore.setManualAutostartConfirmed confirmed=" + confirmed);
preferences(context).edit()
.putBoolean(KEY_MANUAL_AUTOSTART_CONFIRMED, confirmed)
.apply();
}
- static void setManualBatteryUnrestrictedConfirmed(Context context, boolean confirmed) {
+ public static void setManualBatteryUnrestrictedConfirmed(Context context, boolean confirmed) {
Log.d(TAG, "KeepAliveStateStore.setManualBatteryUnrestrictedConfirmed confirmed=" + confirmed);
preferences(context).edit()
.putBoolean(KEY_MANUAL_BATTERY_UNRESTRICTED_CONFIRMED, confirmed)
.apply();
}
- static void setBatteryOptimizationIgnored(Context context, boolean ignored) {
+ public static void setBatteryOptimizationIgnored(Context context, boolean ignored) {
Log.d(TAG, "KeepAliveStateStore.setBatteryOptimizationIgnored ignored=" + ignored);
preferences(context).edit()
.putBoolean(KEY_BATTERY_OPTIMIZATION_IGNORED, ignored)
.apply();
}
- static void setToastOnDatabaseWrite(Context context, boolean enabled) {
+ public static void setToastOnDatabaseWrite(Context context, boolean enabled) {
Log.d(TAG, "KeepAliveStateStore.setToastOnDatabaseWrite enabled=" + enabled);
preferences(context).edit()
.putBoolean(KEY_TOAST_ON_DATABASE_WRITE, enabled)
.apply();
}
- static boolean isToastOnDatabaseWriteEnabled(Context context) {
+ public static boolean isToastOnDatabaseWriteEnabled(Context context) {
return preferences(context).getBoolean(KEY_TOAST_ON_DATABASE_WRITE, false);
}
- static State load(Context context) {
+ public static State load(Context context) {
SharedPreferences prefs = preferences(context);
return new State(
prefs.getBoolean(KEY_ENABLED_BY_USER, false),
@@ -128,17 +128,17 @@ final class KeepAliveStateStore {
return TextUtils.isEmpty(value) ? "" : value;
}
- static final class State {
- final boolean enabledByUser;
- final boolean serviceRunning;
- final long lastHeartbeatMillis;
- final String lastBootEvent;
- final long lastBootTimeMillis;
- final String lastServiceStartFailure;
- final boolean manualAutostartConfirmed;
- final boolean manualBatteryUnrestrictedConfirmed;
- final boolean batteryOptimizationIgnored;
- final boolean toastOnDatabaseWrite;
+ public static final class State {
+ public final boolean enabledByUser;
+ public final boolean serviceRunning;
+ public final long lastHeartbeatMillis;
+ public final String lastBootEvent;
+ public final long lastBootTimeMillis;
+ public final String lastServiceStartFailure;
+ public final boolean manualAutostartConfirmed;
+ public final boolean manualBatteryUnrestrictedConfirmed;
+ public final boolean batteryOptimizationIgnored;
+ public final boolean toastOnDatabaseWrite;
State(
boolean enabledByUser,
diff --git a/app/src/main/java/com/smsreceive/app/SmsKeepAliveService.java b/app/src/main/java/com/smsreceive/app/keepalive/SmsKeepAliveService.java
similarity index 95%
rename from app/src/main/java/com/smsreceive/app/SmsKeepAliveService.java
rename to app/src/main/java/com/smsreceive/app/keepalive/SmsKeepAliveService.java
index 8ec1138..0ebaa68 100644
--- a/app/src/main/java/com/smsreceive/app/SmsKeepAliveService.java
+++ b/app/src/main/java/com/smsreceive/app/keepalive/SmsKeepAliveService.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.keepalive;
import android.app.Service;
import android.content.Context;
@@ -10,6 +10,8 @@ import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
+import com.smsreceive.app.sms.SmsCaptureStore;
+
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@@ -41,7 +43,7 @@ public final class SmsKeepAliveService extends Service {
}
};
- static void start(Context context) {
+ public static void start(Context context) {
Log.d(TAG, "SmsKeepAliveService.start requested sdk=" + Build.VERSION.SDK_INT);
Intent intent = new Intent(context, SmsKeepAliveService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -51,7 +53,7 @@ public final class SmsKeepAliveService extends Service {
}
}
- static void stop(Context context) {
+ public static void stop(Context context) {
Log.d(TAG, "SmsKeepAliveService.stop requested");
context.stopService(new Intent(context, SmsKeepAliveService.class));
}
diff --git a/app/src/main/java/com/smsreceive/app/SmsPollingService.java b/app/src/main/java/com/smsreceive/app/keepalive/SmsPollingService.java
similarity index 94%
rename from app/src/main/java/com/smsreceive/app/SmsPollingService.java
rename to app/src/main/java/com/smsreceive/app/keepalive/SmsPollingService.java
index 0ec0aa9..d285abb 100644
--- a/app/src/main/java/com/smsreceive/app/SmsPollingService.java
+++ b/app/src/main/java/com/smsreceive/app/keepalive/SmsPollingService.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.keepalive;
import android.Manifest;
import android.app.Service;
@@ -12,6 +12,11 @@ import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
+import com.smsreceive.app.feishu.FeishuWebhookClient;
+import com.smsreceive.app.sms.CaptureResult;
+import com.smsreceive.app.sms.SmsCaptureStore;
+import com.smsreceive.app.sms.SmsInboxReader;
+
public final class SmsPollingService extends Service {
private static final String TAG = "[SMS]SmsReceive";
private static final String SOURCE_INBOX_POLLING = "sms_inbox_polling";
@@ -29,7 +34,7 @@ public final class SmsPollingService extends Service {
}
};
- static void start(Context context) {
+ public static void start(Context context) {
Log.d(TAG, "SmsPollingService.start requested sdk=" + Build.VERSION.SDK_INT);
long startTimeMillis = System.currentTimeMillis() - 2_000L;
SmsPollingStateStore.recordStarted(context, startTimeMillis);
@@ -42,7 +47,7 @@ public final class SmsPollingService extends Service {
}
}
- static void stop(Context context) {
+ public static void stop(Context context) {
Log.d(TAG, "SmsPollingService.stop requested");
SmsPollingStateStore.recordStopped(context, "用户停止轮询");
context.stopService(new Intent(context, SmsPollingService.class));
diff --git a/app/src/main/java/com/smsreceive/app/SmsPollingStateStore.java b/app/src/main/java/com/smsreceive/app/keepalive/SmsPollingStateStore.java
similarity index 81%
rename from app/src/main/java/com/smsreceive/app/SmsPollingStateStore.java
rename to app/src/main/java/com/smsreceive/app/keepalive/SmsPollingStateStore.java
index 6cc23db..daa5521 100644
--- a/app/src/main/java/com/smsreceive/app/SmsPollingStateStore.java
+++ b/app/src/main/java/com/smsreceive/app/keepalive/SmsPollingStateStore.java
@@ -1,11 +1,11 @@
-package com.smsreceive.app;
+package com.smsreceive.app.keepalive;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log;
-final class SmsPollingStateStore {
+public final class SmsPollingStateStore {
private static final String TAG = "[SMS]SmsReceive";
private static final String PREFS = "sms_polling";
private static final String KEY_ENABLED_BY_USER = "enabled_by_user";
@@ -22,7 +22,7 @@ final class SmsPollingStateStore {
private SmsPollingStateStore() {
}
- static void recordStarted(Context context, long startTimeMillis) {
+ public static void recordStarted(Context context, long startTimeMillis) {
Log.d(TAG, "SmsPollingStateStore.recordStarted startTime=" + startTimeMillis);
preferences(context).edit()
.putBoolean(KEY_ENABLED_BY_USER, true)
@@ -32,7 +32,7 @@ final class SmsPollingStateStore {
.apply();
}
- static void recordStopped(Context context, String reason) {
+ public static void recordStopped(Context context, String reason) {
Log.d(TAG, "SmsPollingStateStore.recordStopped reason=" + reason);
preferences(context).edit()
.putBoolean(KEY_ENABLED_BY_USER, false)
@@ -41,7 +41,7 @@ final class SmsPollingStateStore {
.apply();
}
- static void recordServiceStopped(Context context, String reason) {
+ public static void recordServiceStopped(Context context, String reason) {
Log.d(TAG, "SmsPollingStateStore.recordServiceStopped reason=" + reason);
preferences(context).edit()
.putBoolean(KEY_RUNNING, false)
@@ -49,13 +49,13 @@ final class SmsPollingStateStore {
.apply();
}
- static void recordServiceRunning(Context context) {
+ public static void recordServiceRunning(Context context) {
preferences(context).edit()
.putBoolean(KEY_RUNNING, true)
.apply();
}
- static void recordHit(Context context, long smsId, long hitTimeMillis) {
+ public static void recordHit(Context context, long smsId, long hitTimeMillis) {
Log.d(TAG, "SmsPollingStateStore.recordHit id=" + smsId + ", time=" + hitTimeMillis);
preferences(context).edit()
.putLong(KEY_LAST_HIT_ID, smsId)
@@ -64,7 +64,7 @@ final class SmsPollingStateStore {
.apply();
}
- static void setIntervalSeconds(Context context, int seconds) {
+ public static void setIntervalSeconds(Context context, int seconds) {
int safeSeconds = clampIntervalSeconds(seconds);
Log.d(TAG, "SmsPollingStateStore.setIntervalSeconds seconds=" + safeSeconds);
preferences(context).edit()
@@ -72,11 +72,11 @@ final class SmsPollingStateStore {
.apply();
}
- static int getIntervalSeconds(Context context) {
+ public static int getIntervalSeconds(Context context) {
return clampIntervalSeconds(preferences(context).getInt(KEY_INTERVAL_SECONDS, DEFAULT_INTERVAL_SECONDS));
}
- static State load(Context context) {
+ public static State load(Context context) {
SharedPreferences prefs = preferences(context);
return new State(
prefs.getBoolean(KEY_ENABLED_BY_USER, false),
@@ -100,14 +100,14 @@ final class SmsPollingStateStore {
return Math.max(MIN_INTERVAL_SECONDS, Math.min(seconds, MAX_INTERVAL_SECONDS));
}
- static final class State {
- final boolean enabledByUser;
- final boolean running;
- final long startTimeMillis;
- final long lastHitId;
- final long lastHitTimeMillis;
- final String lastFailure;
- final int intervalSeconds;
+ public static final class State {
+ public final boolean enabledByUser;
+ public final boolean running;
+ public final long startTimeMillis;
+ public final long lastHitId;
+ public final long lastHitTimeMillis;
+ public final String lastFailure;
+ public final int intervalSeconds;
State(
boolean enabledByUser,
diff --git a/app/src/main/java/com/smsreceive/app/CaptureResult.java b/app/src/main/java/com/smsreceive/app/sms/CaptureResult.java
similarity index 77%
rename from app/src/main/java/com/smsreceive/app/CaptureResult.java
rename to app/src/main/java/com/smsreceive/app/sms/CaptureResult.java
index 39eb183..a2f64e8 100644
--- a/app/src/main/java/com/smsreceive/app/CaptureResult.java
+++ b/app/src/main/java/com/smsreceive/app/sms/CaptureResult.java
@@ -1,15 +1,15 @@
-package com.smsreceive.app;
+package com.smsreceive.app.sms;
-final class CaptureResult {
- static final long UNKNOWN_SMS_PROVIDER_ID = -1L;
+public final class CaptureResult {
+ public static final long UNKNOWN_SMS_PROVIDER_ID = -1L;
- final long receivedAtMillis;
- final long smsProviderId;
- final String sender;
- final String body;
- final VerificationCodeParser.ParseResult parseResult;
- final String source;
- final String failureReason;
+ public final long receivedAtMillis;
+ public final long smsProviderId;
+ public final String sender;
+ public final String body;
+ public final VerificationCodeParser.ParseResult parseResult;
+ public final String source;
+ public final String failureReason;
private CaptureResult(
long receivedAtMillis,
@@ -28,7 +28,7 @@ final class CaptureResult {
this.failureReason = failureReason == null ? "" : failureReason;
}
- static CaptureResult success(
+ public static CaptureResult success(
long receivedAtMillis,
String sender,
String body,
@@ -37,7 +37,7 @@ final class CaptureResult {
return success(receivedAtMillis, UNKNOWN_SMS_PROVIDER_ID, sender, body, parseResult, source);
}
- static CaptureResult success(
+ public static CaptureResult success(
long receivedAtMillis,
long smsProviderId,
String sender,
@@ -47,7 +47,7 @@ final class CaptureResult {
return new CaptureResult(receivedAtMillis, smsProviderId, sender, body, parseResult, source, "");
}
- static CaptureResult failure(
+ public static CaptureResult failure(
long receivedAtMillis,
String sender,
String body,
@@ -56,7 +56,7 @@ final class CaptureResult {
return failure(receivedAtMillis, UNKNOWN_SMS_PROVIDER_ID, sender, body, source, failureReason);
}
- static CaptureResult failure(
+ public static CaptureResult failure(
long receivedAtMillis,
long smsProviderId,
String sender,
diff --git a/app/src/main/java/com/smsreceive/app/SmsCaptureStore.java b/app/src/main/java/com/smsreceive/app/sms/SmsCaptureStore.java
similarity index 83%
rename from app/src/main/java/com/smsreceive/app/SmsCaptureStore.java
rename to app/src/main/java/com/smsreceive/app/sms/SmsCaptureStore.java
index 4b2c111..2aaa797 100644
--- a/app/src/main/java/com/smsreceive/app/SmsCaptureStore.java
+++ b/app/src/main/java/com/smsreceive/app/sms/SmsCaptureStore.java
@@ -1,12 +1,12 @@
-package com.smsreceive.app;
+package com.smsreceive.app.sms;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log;
-final class SmsCaptureStore {
- static final String ACTION_CAPTURE_UPDATED = "com.smsreceive.app.ACTION_CAPTURE_UPDATED";
+public final class SmsCaptureStore {
+ public static final String ACTION_CAPTURE_UPDATED = "com.smsreceive.app.ACTION_CAPTURE_UPDATED";
private static final String TAG = "[SMS]SmsReceive";
private static final String PREFS = "sms_capture";
@@ -25,7 +25,7 @@ final class SmsCaptureStore {
private SmsCaptureStore() {
}
- static void save(Context context, CaptureResult result) {
+ public static void save(Context context, CaptureResult result) {
VerificationCodeParser.ParseResult parse = result.parseResult;
Log.d(TAG, "SmsCaptureStore.save source=" + result.source
+ ", success=" + parse.success
@@ -53,7 +53,7 @@ final class SmsCaptureStore {
editor.apply();
}
- static StoredCapture load(Context context) {
+ public static StoredCapture load(Context context) {
SharedPreferences prefs = preferences(context);
return new StoredCapture(
prefs.getLong(KEY_TIME, 0L),
@@ -66,12 +66,12 @@ final class SmsCaptureStore {
prefs.getString(KEY_BODY_PREVIEW, ""));
}
- static void clear(Context context) {
+ public static void clear(Context context) {
Log.d(TAG, "SmsCaptureStore.clear");
preferences(context).edit().clear().apply();
}
- static DeliveryDiagnostics loadDeliveryDiagnostics(Context context) {
+ public static DeliveryDiagnostics loadDeliveryDiagnostics(Context context) {
SharedPreferences prefs = preferences(context);
return new DeliveryDiagnostics(
prefs.getLong(KEY_LAST_BROADCAST_TIME, 0L),
@@ -101,15 +101,15 @@ final class SmsCaptureStore {
return normalized.length() <= 48 ? normalized : normalized.substring(0, 48) + "...";
}
- static final class StoredCapture {
- final long timeMillis;
- final String sender;
- final String code;
- final String strategy;
- final int confidence;
- final String source;
- final String failure;
- final String bodyPreview;
+ public static final class StoredCapture {
+ public final long timeMillis;
+ public final String sender;
+ public final String code;
+ public final String strategy;
+ public final int confidence;
+ public final String source;
+ public final String failure;
+ public final String bodyPreview;
StoredCapture(
long timeMillis,
@@ -131,10 +131,10 @@ final class SmsCaptureStore {
}
}
- static final class DeliveryDiagnostics {
- final long lastBroadcastTimeMillis;
- final long lastInboxTimeMillis;
- final String lastInboxSource;
+ public static final class DeliveryDiagnostics {
+ public final long lastBroadcastTimeMillis;
+ public final long lastInboxTimeMillis;
+ public final String lastInboxSource;
DeliveryDiagnostics(long lastBroadcastTimeMillis, long lastInboxTimeMillis, String lastInboxSource) {
this.lastBroadcastTimeMillis = lastBroadcastTimeMillis;
@@ -142,7 +142,7 @@ final class SmsCaptureStore {
this.lastInboxSource = lastInboxSource == null ? "" : lastInboxSource;
}
- boolean inboxNewerThanBroadcast() {
+ public boolean inboxNewerThanBroadcast() {
return lastInboxTimeMillis > 0L && lastInboxTimeMillis > lastBroadcastTimeMillis;
}
}
diff --git a/app/src/main/java/com/smsreceive/app/SmsInboxReader.java b/app/src/main/java/com/smsreceive/app/sms/SmsInboxReader.java
similarity index 92%
rename from app/src/main/java/com/smsreceive/app/SmsInboxReader.java
rename to app/src/main/java/com/smsreceive/app/sms/SmsInboxReader.java
index 9b12186..9adee69 100644
--- a/app/src/main/java/com/smsreceive/app/SmsInboxReader.java
+++ b/app/src/main/java/com/smsreceive/app/sms/SmsInboxReader.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.sms;
import android.content.Context;
import android.database.Cursor;
@@ -11,14 +11,14 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
-final class SmsInboxReader {
+public final class SmsInboxReader {
private static final String TAG = "[SMS]SmsReceive";
private static final Uri SMS_INBOX_URI = Uri.parse("content://sms/inbox");
private SmsInboxReader() {
}
- static InboxResult readLatest(Context context) {
+ public static InboxResult readLatest(Context context) {
String[] projection = {
Telephony.Sms._ID,
Telephony.Sms.ADDRESS,
@@ -64,7 +64,7 @@ final class SmsInboxReader {
}
}
- static int logRecentMessages(Context context, int limit) {
+ public static int logRecentMessages(Context context, int limit) {
Uri uri = Telephony.Sms.CONTENT_URI;
String[] projection = {
Telephony.Sms._ID,
@@ -116,11 +116,11 @@ final class SmsInboxReader {
}
}
- static RecentCodeResult findLatestVerificationCode(Context context, int limit) {
+ public static RecentCodeResult findLatestVerificationCode(Context context, int limit) {
return findLatestVerificationCode(context, limit, 0L);
}
- static RecentCodeResult findLatestVerificationCode(Context context, int limit, long minDateMillis) {
+ public static RecentCodeResult findLatestVerificationCode(Context context, int limit, long minDateMillis) {
Uri uri = Telephony.Sms.CONTENT_URI;
String[] projection = {
Telephony.Sms._ID,
@@ -231,13 +231,13 @@ final class SmsInboxReader {
}
}
- static final class InboxResult {
- final boolean success;
- final long id;
- final String sender;
- final String body;
- final long dateMillis;
- final String failureReason;
+ public static final class InboxResult {
+ public final boolean success;
+ public final long id;
+ public final String sender;
+ public final String body;
+ public final long dateMillis;
+ public final String failureReason;
private InboxResult(boolean success, long id, String sender, String body, long dateMillis, String failureReason) {
this.success = success;
@@ -257,15 +257,15 @@ final class SmsInboxReader {
}
}
- static final class RecentCodeResult {
- final boolean success;
- final long id;
- final String sender;
- final String body;
- final long dateMillis;
- final VerificationCodeParser.ParseResult parseResult;
- final int scannedCount;
- final String failureReason;
+ public static final class RecentCodeResult {
+ public final boolean success;
+ public final long id;
+ public final String sender;
+ public final String body;
+ public final long dateMillis;
+ public final VerificationCodeParser.ParseResult parseResult;
+ public final int scannedCount;
+ public final String failureReason;
private RecentCodeResult(
boolean success,
diff --git a/app/src/main/java/com/smsreceive/app/SmsMessageReader.java b/app/src/main/java/com/smsreceive/app/sms/SmsMessageReader.java
similarity index 98%
rename from app/src/main/java/com/smsreceive/app/SmsMessageReader.java
rename to app/src/main/java/com/smsreceive/app/sms/SmsMessageReader.java
index e28864a..dcac92e 100644
--- a/app/src/main/java/com/smsreceive/app/SmsMessageReader.java
+++ b/app/src/main/java/com/smsreceive/app/sms/SmsMessageReader.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.sms;
import android.content.Intent;
import android.provider.Telephony;
diff --git a/app/src/main/java/com/smsreceive/app/SmsReceiver.java b/app/src/main/java/com/smsreceive/app/sms/SmsReceiver.java
similarity index 97%
rename from app/src/main/java/com/smsreceive/app/SmsReceiver.java
rename to app/src/main/java/com/smsreceive/app/sms/SmsReceiver.java
index 78c3540..d1a4b6a 100644
--- a/app/src/main/java/com/smsreceive/app/SmsReceiver.java
+++ b/app/src/main/java/com/smsreceive/app/sms/SmsReceiver.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.sms;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -7,6 +7,8 @@ import android.provider.Telephony;
import android.util.Log;
import android.widget.Toast;
+import com.smsreceive.app.feishu.FeishuWebhookClient;
+
public final class SmsReceiver extends BroadcastReceiver {
private static final String TAG = "[SMS]SmsReceive";
private static final String SOURCE_SYSTEM_BROADCAST = "system_sms_broadcast";
diff --git a/app/src/main/java/com/smsreceive/app/VerificationCodeParser.java b/app/src/main/java/com/smsreceive/app/sms/VerificationCodeParser.java
similarity index 99%
rename from app/src/main/java/com/smsreceive/app/VerificationCodeParser.java
rename to app/src/main/java/com/smsreceive/app/sms/VerificationCodeParser.java
index a3f5d55..249c063 100644
--- a/app/src/main/java/com/smsreceive/app/VerificationCodeParser.java
+++ b/app/src/main/java/com/smsreceive/app/sms/VerificationCodeParser.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.sms;
import java.util.ArrayList;
import java.util.List;
diff --git a/app/src/main/java/com/smsreceive/app/MainActivity.java b/app/src/main/java/com/smsreceive/app/ui/MainActivity.java
similarity index 98%
rename from app/src/main/java/com/smsreceive/app/MainActivity.java
rename to app/src/main/java/com/smsreceive/app/ui/MainActivity.java
index 00c5f30..b504616 100644
--- a/app/src/main/java/com/smsreceive/app/MainActivity.java
+++ b/app/src/main/java/com/smsreceive/app/ui/MainActivity.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.ui;
import android.Manifest;
import android.app.Activity;
@@ -35,6 +35,19 @@ import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
+import com.smsreceive.app.feishu.FeishuWebhookClient;
+import com.smsreceive.app.feishu.FeishuWebhookConfigStore;
+import com.smsreceive.app.feishu.FeishuWebhookPushResult;
+import com.smsreceive.app.keepalive.KeepAliveDatabase;
+import com.smsreceive.app.keepalive.KeepAliveStateStore;
+import com.smsreceive.app.keepalive.SmsKeepAliveService;
+import com.smsreceive.app.keepalive.SmsPollingService;
+import com.smsreceive.app.keepalive.SmsPollingStateStore;
+import com.smsreceive.app.sms.CaptureResult;
+import com.smsreceive.app.sms.SmsCaptureStore;
+import com.smsreceive.app.sms.SmsInboxReader;
+import com.smsreceive.app.sms.VerificationCodeParser;
+
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
diff --git a/app/src/test/java/com/smsreceive/app/FeishuWebhookClientTest.java b/app/src/test/java/com/smsreceive/app/feishu/FeishuWebhookClientTest.java
similarity index 98%
rename from app/src/test/java/com/smsreceive/app/FeishuWebhookClientTest.java
rename to app/src/test/java/com/smsreceive/app/feishu/FeishuWebhookClientTest.java
index 54270d1..5ddcd12 100644
--- a/app/src/test/java/com/smsreceive/app/FeishuWebhookClientTest.java
+++ b/app/src/test/java/com/smsreceive/app/feishu/FeishuWebhookClientTest.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.feishu;
import org.json.JSONObject;
import org.junit.Test;
diff --git a/app/src/test/java/com/smsreceive/app/VerificationCodeParserTest.java b/app/src/test/java/com/smsreceive/app/sms/VerificationCodeParserTest.java
similarity index 98%
rename from app/src/test/java/com/smsreceive/app/VerificationCodeParserTest.java
rename to app/src/test/java/com/smsreceive/app/sms/VerificationCodeParserTest.java
index d13e32f..6c2cde4 100644
--- a/app/src/test/java/com/smsreceive/app/VerificationCodeParserTest.java
+++ b/app/src/test/java/com/smsreceive/app/sms/VerificationCodeParserTest.java
@@ -1,4 +1,4 @@
-package com.smsreceive.app;
+package com.smsreceive.app.sms;
import org.junit.Test;
diff --git a/gradle.properties b/gradle.properties
index f86ba92..dfc6ee8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,4 +2,3 @@ org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
android.useAndroidX=true
android.enableJetifier=false
android.injected.testOnly=false
-android.aapt2FromMavenOverride=/Users/zouchao/Library/Android/sdk/build-tools/30.0.3/aapt2