main #1
@ -2,6 +2,7 @@ package com.smsreceive.app.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
@ -19,21 +20,18 @@ import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Telephony;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.smsreceive.app.R;
|
||||
import com.smsreceive.app.feishu.FeishuWebhookClient;
|
||||
import com.smsreceive.app.feishu.FeishuWebhookConfigStore;
|
||||
import com.smsreceive.app.feishu.FeishuWebhookPushResult;
|
||||
@ -59,22 +57,31 @@ public final class MainActivity extends Activity {
|
||||
private static final long DATABASE_HEARTBEAT_STALE_MILLIS = 30_000L;
|
||||
|
||||
private TextView permissionText;
|
||||
private TextView latestText;
|
||||
private TextView googlePlayText;
|
||||
private TextView keepAliveText;
|
||||
private TextView databaseHeartbeatText;
|
||||
private TextView deliveryDiagnosticsText;
|
||||
private TextView feishuPushText;
|
||||
private TextView latestText;
|
||||
private Button keepAliveButton;
|
||||
private Button autostartConfirmButton;
|
||||
private Button batteryConfirmButton;
|
||||
private Button pollingButton;
|
||||
private RadioButton toastOnDatabaseWriteRadio;
|
||||
private CheckBox feishuPushEnabledCheckBox;
|
||||
private CheckBox autostartConfirmCheckBox;
|
||||
private CheckBox batteryConfirmCheckBox;
|
||||
private EditText feishuWebhookIdEdit;
|
||||
private EditText feishuSecretEdit;
|
||||
private EditText pollingIntervalEdit;
|
||||
private AlertDialog debugInfoDialog;
|
||||
private View debugInfoView;
|
||||
private long lastInboxSmsId = -1L;
|
||||
private String googlePlayTextValue = "";
|
||||
private String keepAliveTextValue = "";
|
||||
private String databaseHeartbeatTextValue = "";
|
||||
private String deliveryDiagnosticsTextValue = "";
|
||||
private String feishuPushTextValue = "";
|
||||
private int databaseHeartbeatBackgroundColor = 0xFFFFFFFF;
|
||||
private int feishuPushBackgroundColor = 0xFFFFFFFF;
|
||||
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
private final BroadcastReceiver updateReceiver = new BroadcastReceiver() {
|
||||
@ -91,11 +98,15 @@ public final class MainActivity extends Activity {
|
||||
readLatestInboxSms(SOURCE_INBOX_OBSERVER, true);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Log.d(TAG, "MainActivity.onCreate");
|
||||
setContentView(createContentView());
|
||||
setContentView(R.layout.activity_main);
|
||||
bindMainViews();
|
||||
bindMainActions();
|
||||
refreshUi();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -139,189 +150,95 @@ public final class MainActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private View createContentView() {
|
||||
ScrollView scrollView = new ScrollView(this);
|
||||
scrollView.setFillViewport(true);
|
||||
private void bindMainViews() {
|
||||
permissionText = findViewById(R.id.permission_text);
|
||||
latestText = findViewById(R.id.latest_text);
|
||||
keepAliveButton = findViewById(R.id.keep_alive_button);
|
||||
toastOnDatabaseWriteRadio = findViewById(R.id.toast_database_write_radio);
|
||||
pollingButton = findViewById(R.id.polling_button);
|
||||
feishuPushEnabledCheckBox = findViewById(R.id.feishu_push_enabled_checkbox);
|
||||
autostartConfirmCheckBox = findViewById(R.id.autostart_confirm_checkbox);
|
||||
batteryConfirmCheckBox = findViewById(R.id.battery_confirm_checkbox);
|
||||
feishuWebhookIdEdit = findViewById(R.id.feishu_webhook_id_edit);
|
||||
feishuSecretEdit = findViewById(R.id.feishu_secret_edit);
|
||||
pollingIntervalEdit = findViewById(R.id.polling_interval_edit);
|
||||
}
|
||||
|
||||
LinearLayout root = new LinearLayout(this);
|
||||
root.setOrientation(LinearLayout.VERTICAL);
|
||||
root.setPadding(dp(20), dp(24), dp(20), dp(24));
|
||||
scrollView.addView(root, new ScrollView.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
TextView title = new TextView(this);
|
||||
title.setText("短信接收");
|
||||
title.setTextSize(24);
|
||||
title.setTextColor(0xFF17202A);
|
||||
title.setGravity(Gravity.START);
|
||||
root.addView(title, matchWrap());
|
||||
|
||||
TextView subtitle = new TextView(this);
|
||||
subtitle.setText("主路径:RECEIVE_SMS + SMS_RECEIVED_ACTION。收到短信后保存短信原文和诊断摘要。");
|
||||
subtitle.setTextSize(14);
|
||||
subtitle.setTextColor(0xFF5F6B7A);
|
||||
subtitle.setPadding(0, dp(6), 0, dp(16));
|
||||
root.addView(subtitle, matchWrap());
|
||||
|
||||
permissionText = section(root, "权限状态");
|
||||
googlePlayText = section(root, "Google API 诊断");
|
||||
keepAliveText = section(root, "后台保活状态");
|
||||
databaseHeartbeatText = section(root, "数据库心跳诊断");
|
||||
deliveryDiagnosticsText = section(root, "短信广播诊断");
|
||||
feishuPushText = section(root, "飞书推送状态");
|
||||
latestText = section(root, "最近结果");
|
||||
|
||||
LinearLayout actions = new LinearLayout(this);
|
||||
actions.setOrientation(LinearLayout.VERTICAL);
|
||||
actions.setPadding(0, dp(12), 0, 0);
|
||||
root.addView(actions, matchWrap());
|
||||
|
||||
Button requestPermissionButton = button("申请短信权限");
|
||||
requestPermissionButton.setOnClickListener(v -> requestSmsPermission());
|
||||
actions.addView(requestPermissionButton, matchWrap());
|
||||
|
||||
keepAliveButton = button("开启常驻保活");
|
||||
private void bindMainActions() {
|
||||
findViewById(R.id.request_permission_button).setOnClickListener(v -> requestSmsPermission());
|
||||
findViewById(R.id.debug_info_button).setOnClickListener(v -> showDebugInfoDialog());
|
||||
keepAliveButton.setOnClickListener(v -> toggleKeepAlive());
|
||||
actions.addView(keepAliveButton, matchWrap());
|
||||
|
||||
toastOnDatabaseWriteRadio = new RadioButton(this);
|
||||
toastOnDatabaseWriteRadio.setText("每次写入数据库时弹 Toast");
|
||||
toastOnDatabaseWriteRadio.setTextSize(14);
|
||||
toastOnDatabaseWriteRadio.setTextColor(0xFF27313F);
|
||||
toastOnDatabaseWriteRadio.setOnClickListener(v -> toggleToastOnDatabaseWrite());
|
||||
actions.addView(toastOnDatabaseWriteRadio, matchWrap());
|
||||
|
||||
Button readInboxButton = button("读取最新短信");
|
||||
readInboxButton.setOnClickListener(v -> readLatestInboxSms(SOURCE_INBOX_MANUAL, true));
|
||||
actions.addView(readInboxButton, matchWrap());
|
||||
|
||||
pollingButton = button("开始短信轮询");
|
||||
findViewById(R.id.read_inbox_button).setOnClickListener(v -> readLatestInboxSms(SOURCE_INBOX_MANUAL, true));
|
||||
pollingButton.setOnClickListener(v -> togglePolling());
|
||||
actions.addView(pollingButton, matchWrap());
|
||||
|
||||
pollingIntervalEdit = new EditText(this);
|
||||
pollingIntervalEdit.setHint("轮询间隔秒数,默认 1");
|
||||
pollingIntervalEdit.setSingleLine(true);
|
||||
pollingIntervalEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
actions.addView(pollingIntervalEdit, matchWrap());
|
||||
|
||||
feishuPushEnabledCheckBox = new CheckBox(this);
|
||||
feishuPushEnabledCheckBox.setText("开启飞书远端推送");
|
||||
feishuPushEnabledCheckBox.setTextSize(14);
|
||||
feishuPushEnabledCheckBox.setTextColor(0xFF27313F);
|
||||
actions.addView(feishuPushEnabledCheckBox, matchWrap());
|
||||
|
||||
feishuWebhookIdEdit = new EditText(this);
|
||||
feishuWebhookIdEdit.setHint("飞书 webhook id");
|
||||
feishuWebhookIdEdit.setSingleLine(true);
|
||||
actions.addView(feishuWebhookIdEdit, matchWrap());
|
||||
|
||||
feishuSecretEdit = new EditText(this);
|
||||
feishuSecretEdit.setHint("飞书 webhook secret");
|
||||
feishuSecretEdit.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
feishuSecretEdit.setSingleLine(true);
|
||||
actions.addView(feishuSecretEdit, matchWrap());
|
||||
|
||||
Button saveFeishuButton = button("保存飞书配置");
|
||||
saveFeishuButton.setOnClickListener(v -> saveFeishuConfigFromUi());
|
||||
actions.addView(saveFeishuButton, matchWrap());
|
||||
|
||||
Button testFeishuButton = button("测试飞书推送");
|
||||
testFeishuButton.setOnClickListener(v -> testFeishuPush());
|
||||
actions.addView(testFeishuButton, matchWrap());
|
||||
|
||||
Button settingsButton = button("打开应用权限设置");
|
||||
settingsButton.setOnClickListener(v -> openAppSettings());
|
||||
actions.addView(settingsButton, matchWrap());
|
||||
|
||||
Button batterySettingsButton = button("打开电池优化设置");
|
||||
batterySettingsButton.setOnClickListener(v -> openBatteryOptimizationSettings());
|
||||
actions.addView(batterySettingsButton, matchWrap());
|
||||
|
||||
Button requestBatteryButton = button("请求忽略电池优化");
|
||||
requestBatteryButton.setOnClickListener(v -> requestIgnoreBatteryOptimizations());
|
||||
actions.addView(requestBatteryButton, matchWrap());
|
||||
|
||||
Button xiaomiAutostartButton = button("打开小米自启动设置");
|
||||
xiaomiAutostartButton.setOnClickListener(v -> openXiaomiAutostartSettings());
|
||||
actions.addView(xiaomiAutostartButton, matchWrap());
|
||||
|
||||
autostartConfirmButton = button("确认已开启小米自启动");
|
||||
autostartConfirmButton.setOnClickListener(v -> toggleManualAutostartConfirmed());
|
||||
actions.addView(autostartConfirmButton, matchWrap());
|
||||
|
||||
batteryConfirmButton = button("确认省电策略已设为无限制");
|
||||
batteryConfirmButton.setOnClickListener(v -> toggleManualBatteryConfirmed());
|
||||
actions.addView(batteryConfirmButton, matchWrap());
|
||||
|
||||
Button clearButton = button("清空最近结果");
|
||||
clearButton.setOnClickListener(v -> {
|
||||
findViewById(R.id.save_feishu_button).setOnClickListener(v -> saveFeishuConfigFromUi());
|
||||
findViewById(R.id.test_feishu_button).setOnClickListener(v -> testFeishuPush());
|
||||
findViewById(R.id.settings_button).setOnClickListener(v -> openAppSettings());
|
||||
findViewById(R.id.battery_settings_button).setOnClickListener(v -> openBatteryOptimizationSettings());
|
||||
findViewById(R.id.request_battery_button).setOnClickListener(v -> requestIgnoreBatteryOptimizations());
|
||||
findViewById(R.id.xiaomi_autostart_button).setOnClickListener(v -> openXiaomiAutostartSettings());
|
||||
autostartConfirmCheckBox.setOnClickListener(v -> toggleManualAutostartConfirmed());
|
||||
batteryConfirmCheckBox.setOnClickListener(v -> toggleManualBatteryConfirmed());
|
||||
findViewById(R.id.clear_button).setOnClickListener(v -> {
|
||||
SmsCaptureStore.clear(this);
|
||||
Toast.makeText(this, "已清空最近结果", Toast.LENGTH_SHORT).show();
|
||||
refreshUi();
|
||||
});
|
||||
actions.addView(clearButton, matchWrap());
|
||||
|
||||
Button refreshButton = button("刷新状态");
|
||||
refreshButton.setOnClickListener(v -> refreshUi());
|
||||
actions.addView(refreshButton, matchWrap());
|
||||
|
||||
return scrollView;
|
||||
findViewById(R.id.refresh_button).setOnClickListener(v -> refreshUi());
|
||||
}
|
||||
|
||||
private TextView section(LinearLayout root, String label) {
|
||||
TextView title = new TextView(this);
|
||||
title.setText(label);
|
||||
title.setTextSize(16);
|
||||
title.setTextColor(0xFF17202A);
|
||||
title.setPadding(0, dp(12), 0, dp(4));
|
||||
root.addView(title, matchWrap());
|
||||
|
||||
TextView value = new TextView(this);
|
||||
value.setTextSize(14);
|
||||
value.setTextColor(0xFF27313F);
|
||||
value.setLineSpacing(dp(2), 1.0f);
|
||||
value.setPadding(dp(12), dp(10), dp(12), dp(10));
|
||||
value.setBackgroundColor(0xFFFFFFFF);
|
||||
root.addView(value, matchWrap());
|
||||
return value;
|
||||
private void showDebugInfoDialog() {
|
||||
if (debugInfoDialog == null) {
|
||||
debugInfoView = LayoutInflater.from(this).inflate(R.layout.dialog_debug_info, null);
|
||||
googlePlayText = debugInfoView.findViewById(R.id.google_play_text);
|
||||
keepAliveText = debugInfoView.findViewById(R.id.keep_alive_text);
|
||||
databaseHeartbeatText = debugInfoView.findViewById(R.id.database_heartbeat_text);
|
||||
deliveryDiagnosticsText = debugInfoView.findViewById(R.id.delivery_diagnostics_text);
|
||||
feishuPushText = debugInfoView.findViewById(R.id.feishu_push_text);
|
||||
debugInfoDialog = new AlertDialog.Builder(this)
|
||||
.setTitle("调试信息")
|
||||
.setView(debugInfoView)
|
||||
.setPositiveButton("关闭", null)
|
||||
.create();
|
||||
}
|
||||
applyDebugInfoState();
|
||||
debugInfoDialog.show();
|
||||
}
|
||||
|
||||
private Button button(String text) {
|
||||
Button button = new Button(this);
|
||||
button.setText(text);
|
||||
button.setAllCaps(false);
|
||||
return button;
|
||||
}
|
||||
|
||||
private LinearLayout.LayoutParams matchWrap() {
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.setMargins(0, dp(4), 0, dp(4));
|
||||
return params;
|
||||
private void applyDebugInfoState() {
|
||||
if (googlePlayText == null) {
|
||||
return;
|
||||
}
|
||||
googlePlayText.setText(googlePlayTextValue);
|
||||
keepAliveText.setText(keepAliveTextValue);
|
||||
databaseHeartbeatText.setText(databaseHeartbeatTextValue);
|
||||
databaseHeartbeatText.setBackgroundColor(databaseHeartbeatBackgroundColor);
|
||||
deliveryDiagnosticsText.setText(deliveryDiagnosticsTextValue);
|
||||
feishuPushText.setText(feishuPushTextValue);
|
||||
feishuPushText.setBackgroundColor(feishuPushBackgroundColor);
|
||||
}
|
||||
|
||||
private void refreshUi() {
|
||||
boolean receiveGranted = hasReceiveSmsPermission();
|
||||
boolean readGranted = hasReadSmsPermission();
|
||||
boolean googlePlayInstalled = isGooglePlayServicesInstalled();
|
||||
Log.d(TAG, "refreshUi receiveSmsPermissionGranted=" + receiveGranted
|
||||
+ ", readSmsPermissionGranted=" + readGranted
|
||||
+ ", googlePlayInstalled=" + isGooglePlayServicesInstalled());
|
||||
+ ", googlePlayInstalled=" + googlePlayInstalled);
|
||||
permissionText.setText("RECEIVE_SMS:" + (receiveGranted ? "已授权" : "未授权")
|
||||
+ "\nREAD_SMS:" + (readGranted ? "已授权" : "未授权")
|
||||
+ "\n说明:如果 receiver 收不到广播,前台会用 READ_SMS 读取最新收件箱作为兜底。");
|
||||
|
||||
googlePlayText.setText(isGooglePlayServicesInstalled()
|
||||
googlePlayTextValue = googlePlayInstalled
|
||||
? "已检测到 com.google.android.gms。SMS User Consent / Retriever 可作为后续备选路径验证。"
|
||||
: "未检测到 com.google.android.gms。当前实现不依赖 Google API,主路径仍是系统短信广播。");
|
||||
: "未检测到 com.google.android.gms。当前实现不依赖 Google API,主路径仍是系统短信广播。";
|
||||
|
||||
refreshKeepAliveUi();
|
||||
refreshDatabaseHeartbeatUi();
|
||||
refreshDeliveryDiagnosticsUi();
|
||||
refreshPollingUi();
|
||||
refreshFeishuPushUi();
|
||||
applyDebugInfoState();
|
||||
|
||||
SmsCaptureStore.StoredCapture capture = SmsCaptureStore.load(this);
|
||||
if (capture.timeMillis <= 0L) {
|
||||
@ -352,15 +269,9 @@ public final class MainActivity extends Activity {
|
||||
+ ", notificationsEnabled=" + areNotificationsEnabled()
|
||||
+ ", manualAutostart=" + state.manualAutostartConfirmed
|
||||
+ ", manualBatteryUnrestricted=" + state.manualBatteryUnrestrictedConfirmed);
|
||||
if (keepAliveButton != null) {
|
||||
keepAliveButton.setText(state.enabledByUser ? "关闭常驻保活" : "开启常驻保活");
|
||||
}
|
||||
if (autostartConfirmButton != null) {
|
||||
autostartConfirmButton.setText(state.manualAutostartConfirmed ? "取消自启动确认" : "确认已开启小米自启动");
|
||||
}
|
||||
if (batteryConfirmButton != null) {
|
||||
batteryConfirmButton.setText(state.manualBatteryUnrestrictedConfirmed ? "取消省电无限制确认" : "确认省电策略已设为无限制");
|
||||
}
|
||||
keepAliveButton.setText(state.enabledByUser ? "关闭常驻保活" : "开启常驻保活");
|
||||
autostartConfirmCheckBox.setChecked(state.manualAutostartConfirmed);
|
||||
batteryConfirmCheckBox.setChecked(state.manualBatteryUnrestrictedConfirmed);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("用户开关:").append(state.enabledByUser ? "已开启" : "未开启").append('\n');
|
||||
@ -376,14 +287,12 @@ public final class MainActivity extends Activity {
|
||||
builder.append("通知可见性:").append(areNotificationsEnabled() ? "系统允许通知" : "通知可能被关闭").append('\n');
|
||||
builder.append("小米自启动:").append(state.manualAutostartConfirmed ? "已人工确认" : "未确认").append('\n');
|
||||
builder.append("省电无限制:").append(state.manualBatteryUnrestrictedConfirmed ? "已人工确认" : "未确认");
|
||||
keepAliveText.setText(builder.toString());
|
||||
keepAliveTextValue = builder.toString();
|
||||
}
|
||||
|
||||
private void refreshDatabaseHeartbeatUi() {
|
||||
KeepAliveStateStore.State state = KeepAliveStateStore.load(this);
|
||||
if (toastOnDatabaseWriteRadio != null) {
|
||||
toastOnDatabaseWriteRadio.setChecked(state.toastOnDatabaseWrite);
|
||||
}
|
||||
toastOnDatabaseWriteRadio.setChecked(state.toastOnDatabaseWrite);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long lastActiveTime = KeepAliveDatabase.readLastActiveTime(this);
|
||||
@ -402,7 +311,7 @@ public final class MainActivity extends Activity {
|
||||
if (lastActiveTime <= 0L) {
|
||||
builder.append("最后写入:-").append('\n');
|
||||
builder.append("判断:数据库还没有 lastActiveTime。开启常驻保活后会开始写入。");
|
||||
databaseHeartbeatText.setBackgroundColor(0xFFFFFFFF);
|
||||
databaseHeartbeatBackgroundColor = 0xFFFFFFFF;
|
||||
} else {
|
||||
builder.append("最后写入:").append(formatTimeWithMillis(lastActiveTime)).append('\n');
|
||||
builder.append("距离现在:").append(gapMillis).append(" ms").append('\n');
|
||||
@ -412,13 +321,13 @@ public final class MainActivity extends Activity {
|
||||
.append(",大约在此后 ")
|
||||
.append(DATABASE_HEARTBEAT_INTERVAL_MILLIS / 1000L)
|
||||
.append(" 秒内停止写入。");
|
||||
databaseHeartbeatText.setBackgroundColor(0xFFFFE0E0);
|
||||
databaseHeartbeatBackgroundColor = 0xFFFFE0E0;
|
||||
} else {
|
||||
builder.append("判断:数据库心跳仍在正常窗口内。");
|
||||
databaseHeartbeatText.setBackgroundColor(0xFFE8F5E9);
|
||||
databaseHeartbeatBackgroundColor = 0xFFE8F5E9;
|
||||
}
|
||||
}
|
||||
databaseHeartbeatText.setText(builder.toString());
|
||||
databaseHeartbeatTextValue = builder.toString();
|
||||
}
|
||||
|
||||
private void refreshDeliveryDiagnosticsUi() {
|
||||
@ -436,15 +345,13 @@ public final class MainActivity extends Activity {
|
||||
} else {
|
||||
builder.append("判断:暂无收件箱新于广播的异常记录。");
|
||||
}
|
||||
deliveryDiagnosticsText.setText(builder.toString());
|
||||
deliveryDiagnosticsTextValue = builder.toString();
|
||||
}
|
||||
|
||||
private void refreshPollingUi() {
|
||||
SmsPollingStateStore.State state = SmsPollingStateStore.load(this);
|
||||
if (pollingButton != null) {
|
||||
pollingButton.setText(state.enabledByUser ? "停止短信轮询" : "开始短信轮询");
|
||||
}
|
||||
if (pollingIntervalEdit != null && !pollingIntervalEdit.hasFocus()) {
|
||||
pollingButton.setText(state.enabledByUser ? "停止短信轮询" : "开始短信轮询");
|
||||
if (!pollingIntervalEdit.hasFocus()) {
|
||||
pollingIntervalEdit.setText(String.valueOf(state.intervalSeconds));
|
||||
}
|
||||
Log.d(TAG, "refreshPollingUi enabled=" + state.enabledByUser
|
||||
@ -460,13 +367,11 @@ public final class MainActivity extends Activity {
|
||||
FeishuWebhookConfigStore.Config config = FeishuWebhookConfigStore.loadConfig(this);
|
||||
FeishuWebhookConfigStore.LastResult lastResult = FeishuWebhookConfigStore.loadLastResult(this);
|
||||
FeishuWebhookConfigStore.LastPushedSms lastPushedSms = FeishuWebhookConfigStore.loadLastPushedSms(this);
|
||||
if (feishuPushEnabledCheckBox != null) {
|
||||
feishuPushEnabledCheckBox.setChecked(config.enabled);
|
||||
}
|
||||
if (feishuWebhookIdEdit != null && !feishuWebhookIdEdit.hasFocus()) {
|
||||
feishuPushEnabledCheckBox.setChecked(config.enabled);
|
||||
if (!feishuWebhookIdEdit.hasFocus()) {
|
||||
feishuWebhookIdEdit.setText(config.webhookId);
|
||||
}
|
||||
if (feishuSecretEdit != null && !feishuSecretEdit.hasFocus()) {
|
||||
if (!feishuSecretEdit.hasFocus()) {
|
||||
feishuSecretEdit.setText(config.secret);
|
||||
}
|
||||
|
||||
@ -499,8 +404,8 @@ public final class MainActivity extends Activity {
|
||||
boolean configIssue = !config.enabled || !config.hasWebhookId() || !config.hasSecret()
|
||||
|| FeishuWebhookPushResult.STATUS_DISABLED.equals(lastResult.status)
|
||||
|| FeishuWebhookPushResult.STATUS_MISSING_CONFIG.equals(lastResult.status);
|
||||
feishuPushText.setBackgroundColor(configIssue ? 0xFFFFE0E0 : 0xFFFFFFFF);
|
||||
feishuPushText.setText(builder.toString());
|
||||
feishuPushBackgroundColor = configIssue ? 0xFFFFE0E0 : 0xFFFFFFFF;
|
||||
feishuPushTextValue = builder.toString();
|
||||
}
|
||||
|
||||
private void requestSmsPermission() {
|
||||
@ -562,16 +467,14 @@ public final class MainActivity extends Activity {
|
||||
boolean enabled = !state.toastOnDatabaseWrite;
|
||||
Log.d(TAG, "toggleToastOnDatabaseWrite enabled=" + enabled);
|
||||
KeepAliveStateStore.setToastOnDatabaseWrite(this, enabled);
|
||||
if (toastOnDatabaseWriteRadio != null) {
|
||||
toastOnDatabaseWriteRadio.setChecked(enabled);
|
||||
}
|
||||
toastOnDatabaseWriteRadio.setChecked(enabled);
|
||||
refreshUi();
|
||||
}
|
||||
|
||||
private void saveFeishuConfigFromUi() {
|
||||
boolean enabled = feishuPushEnabledCheckBox != null && feishuPushEnabledCheckBox.isChecked();
|
||||
String webhookId = feishuWebhookIdEdit == null ? "" : feishuWebhookIdEdit.getText().toString();
|
||||
String secret = feishuSecretEdit == null ? "" : feishuSecretEdit.getText().toString();
|
||||
boolean enabled = feishuPushEnabledCheckBox.isChecked();
|
||||
String webhookId = feishuWebhookIdEdit.getText().toString();
|
||||
String secret = feishuSecretEdit.getText().toString();
|
||||
Log.d(TAG, "saveFeishuConfigFromUi enabled=" + enabled
|
||||
+ ", webhookConfigured=" + !TextUtils.isEmpty(webhookId)
|
||||
+ ", secretConfigured=" + !TextUtils.isEmpty(secret));
|
||||
@ -664,14 +567,12 @@ public final class MainActivity extends Activity {
|
||||
private int savePollingIntervalFromUi() {
|
||||
int intervalSeconds = parsePollingIntervalSeconds();
|
||||
SmsPollingStateStore.setIntervalSeconds(this, intervalSeconds);
|
||||
if (pollingIntervalEdit != null && !pollingIntervalEdit.hasFocus()) {
|
||||
pollingIntervalEdit.setText(String.valueOf(intervalSeconds));
|
||||
}
|
||||
pollingIntervalEdit.setText(String.valueOf(intervalSeconds));
|
||||
return intervalSeconds;
|
||||
}
|
||||
|
||||
private int parsePollingIntervalSeconds() {
|
||||
String raw = pollingIntervalEdit == null ? "" : pollingIntervalEdit.getText().toString().trim();
|
||||
String raw = pollingIntervalEdit.getText().toString().trim();
|
||||
if (TextUtils.isEmpty(raw)) {
|
||||
return 1;
|
||||
}
|
||||
@ -702,7 +603,7 @@ public final class MainActivity extends Activity {
|
||||
Log.d(TAG, "startPolling via SmsPollingService");
|
||||
SmsPollingService.start(this);
|
||||
Toast.makeText(this,
|
||||
"已启动后台短信轮询,间隔 " + intervalSeconds + " 秒",
|
||||
"已启动后台短信轮询,间隔 " + intervalSeconds + " 秒",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
refreshUi();
|
||||
}
|
||||
@ -832,8 +733,4 @@ public final class MainActivity extends Activity {
|
||||
}
|
||||
return "***" + sender.substring(sender.length() - 4);
|
||||
}
|
||||
|
||||
private int dp(int value) {
|
||||
return (int) (value * getResources().getDisplayMetrics().density + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
289
app/src/main/res/layout/activity_main.xml
Normal file
289
app/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,289 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/screen_bg"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingBottom="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="短信接收"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="主路径:RECEIVE_SMS + SMS_RECEIVED_ACTION。收到短信后保存短信原文和诊断摘要。"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="权限状态"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/permission_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="@android:color/white"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:padding="12dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="最近结果"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/latest_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="@android:color/white"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:padding="12dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/debug_info_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="调试信息"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/request_permission_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="申请短信权限"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/keep_alive_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="开启常驻保活"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/toast_database_write_radio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="每次写入数据库时弹 Toast"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/read_inbox_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="读取最新短信"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/polling_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="开始短信轮询"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/polling_interval_edit"
|
||||
android:layout_width="96dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:hint="默认1"
|
||||
android:inputType="number"
|
||||
android:maxLines="1" />
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/feishu_push_enabled_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="开启飞书远端推送"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/feishu_webhook_id_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:hint="飞书 webhook id"
|
||||
android:maxLines="1" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/feishu_secret_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:hint="飞书 webhook secret"
|
||||
android:inputType="textPassword"
|
||||
android:maxLines="1" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/save_feishu_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="保存飞书配置"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/test_feishu_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="测试飞书推送"
|
||||
android:textAllCaps="false" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/settings_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="打开应用权限设置"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/battery_settings_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="打开电池优化设置"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/battery_confirm_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:text="确认省电策略无限制"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/request_battery_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="请求忽略电池优化"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/xiaomi_autostart_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="打开小米自启动设置"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/autostart_confirm_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:text="确认自启动开启"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/clear_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="清空最近结果"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/refresh_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="刷新状态"
|
||||
android:textAllCaps="false" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
110
app/src/main/res/layout/dialog_debug_info.xml
Normal file
110
app/src/main/res/layout/dialog_debug_info.xml
Normal file
@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Google API 诊断"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/google_play_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="@android:color/white"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:padding="12dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="后台保活状态"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/keep_alive_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="@android:color/white"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:padding="12dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="数据库心跳诊断"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/database_heartbeat_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="@android:color/white"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:padding="12dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="短信广播诊断"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/delivery_diagnostics_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="@android:color/white"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:padding="12dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="飞书推送状态"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/feishu_push_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="@android:color/white"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:padding="12dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
Loading…
x
Reference in New Issue
Block a user