调整包结构
This commit is contained in:
parent
790afd679e
commit
95a3c6d8c4
@ -1,4 +1,4 @@
|
||||
package com.smsreceive.app;
|
||||
package com.smsreceive.app.sms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
@ -15,7 +15,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name=".ui.MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@ -25,7 +25,7 @@
|
||||
</activity>
|
||||
|
||||
<receiver
|
||||
android:name=".SmsReceiver"
|
||||
android:name=".sms.SmsReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BROADCAST_SMS">
|
||||
@ -35,7 +35,7 @@
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".BootReceiver"
|
||||
android:name=".keepalive.BootReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
@ -46,12 +46,12 @@
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".SmsKeepAliveService"
|
||||
android:name=".keepalive.SmsKeepAliveService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<service
|
||||
android:name=".SmsPollingService"
|
||||
android:name=".keepalive.SmsPollingService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
@ -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;
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.smsreceive.app;
|
||||
package com.smsreceive.app.keepalive;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@ -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,
|
||||
@ -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";
|
||||
@ -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,
|
||||
@ -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));
|
||||
}
|
||||
@ -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));
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
@ -1,4 +1,4 @@
|
||||
package com.smsreceive.app;
|
||||
package com.smsreceive.app.sms;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.provider.Telephony;
|
||||
@ -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";
|
||||
@ -1,4 +1,4 @@
|
||||
package com.smsreceive.app;
|
||||
package com.smsreceive.app.sms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -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;
|
||||
@ -1,4 +1,4 @@
|
||||
package com.smsreceive.app;
|
||||
package com.smsreceive.app.feishu;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
@ -1,4 +1,4 @@
|
||||
package com.smsreceive.app;
|
||||
package com.smsreceive.app.sms;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user