diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a62fed5..c9d3f36 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,6 +11,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/assets/test_shell_commands.sh b/app/src/main/assets/test_shell_commands.sh
new file mode 100644
index 0000000..c29a8c5
--- /dev/null
+++ b/app/src/main/assets/test_shell_commands.sh
@@ -0,0 +1,23 @@
+#!/system/bin/sh
+
+# Shell命令功能测试脚本
+
+echo "=== Shell命令功能测试 ==="
+
+# 测试基本命令
+echo "1. 测试基本命令:"
+which am
+echo "am命令路径: $?"
+
+which pm
+echo "pm命令路径: $?"
+
+# 测试应用启动命令
+echo "2. 测试应用启动命令:"
+echo "准备启动应用..."
+
+# 获取当前包名
+echo "3. 当前应用信息:"
+dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp' | head -5
+
+echo "=== 测试完成 ==="
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/MainActivity.java b/app/src/main/java/com/ouxuan/oxface/MainActivity.java
index 1a247b4..9fa8df1 100644
--- a/app/src/main/java/com/ouxuan/oxface/MainActivity.java
+++ b/app/src/main/java/com/ouxuan/oxface/MainActivity.java
@@ -3,12 +3,15 @@ package com.ouxuan.oxface;
import androidx.appcompat.app.AppCompatActivity;
import android.animation.ObjectAnimator;
import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.InputType;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
@@ -34,6 +37,7 @@ import com.ouxuan.oxface.network.callback.NetworkCallback;
import com.ouxuan.oxface.network.model.ApiResponse;
import com.ouxuan.oxface.network.utils.NetworkUtils;
import com.ouxuan.oxface.utils.KeepAliveManager;
+import com.ouxuan.oxface.utils.AutoStartManager;
import com.ouxuan.oxface.utils.LogManager;
import com.ouxuan.oxface.utils.UtilCodeHelper;
@@ -42,6 +46,8 @@ import org.json.JSONObject;
public class MainActivity extends AppCompatActivity {
+ private static final String TAG = "MainActivity";
+
private EditText editTextUsername;
private EditText editTextPassword;
private View buttonLogin;
@@ -51,6 +57,7 @@ public class MainActivity extends AppCompatActivity {
private LoginDataManager loginDataManager; // 登录数据管理器
private DeviceSelectDataManager deviceSelectDataManager; // 设备选择数据管理器
private KeepAliveManager keepAliveManager; // 保持活跃管理器
+ private AutoStartManager autoStartManager; // 自启动管理器
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -78,9 +85,16 @@ public class MainActivity extends AppCompatActivity {
keepAliveManager = KeepAliveManager.getInstance(this);
keepAliveManager.startKeepAlive(this);
+ // 初始化自启动管理器并检查权限
+ autoStartManager = AutoStartManager.getInstance(this);
+ autoStartManager.checkAndRequestAutoStartPermission();
+
// 记录应用启动
LogManager.logOperation("MainActivity", "主界面已初始化,开始24小时无人值守模式");
+ // 检查是否为自启动
+ checkAutoStartStatus();
+
// 检查是否可以自动登录
checkAutoLogin();
@@ -108,6 +122,40 @@ public class MainActivity extends AppCompatActivity {
}
/**
+ * 检查自启动状态
+ */
+ private void checkAutoStartStatus() {
+ Intent intent = getIntent();
+ if (intent != null) {
+ boolean isAutoStart = intent.getBooleanExtra("auto_start", false);
+ if (isAutoStart) {
+ String bootReason = intent.getStringExtra("boot_reason");
+ String startSource = intent.getStringExtra("start_source");
+ long bootTime = intent.getLongExtra("boot_time", 0);
+ long serviceStartTime = intent.getLongExtra("service_start_time", 0);
+
+ LogManager.logOperation("MainActivity", "检测到自动启动:" +
+ (bootReason != null ? bootReason : "无") +
+ ", 来源:" + (startSource != null ? startSource : "直接启动"));
+
+ // 显示自启动提示
+ if ("system_reboot".equals(bootReason)) {
+ showToast("系统重启后自动恢复,24小时无人值守模式已启动");
+ } else {
+ showToast("应用自动启动成功");
+ }
+
+ // 清除Intent中的自启动标识,防止重复处理
+ intent.removeExtra("auto_start");
+ intent.removeExtra("boot_reason");
+ intent.removeExtra("start_source");
+ intent.removeExtra("boot_time");
+ intent.removeExtra("service_start_time");
+ }
+ }
+ }
+
+ /**
* 检查是否可以自动登录
*/
private void checkAutoLogin() {
@@ -714,11 +762,108 @@ public class MainActivity extends AppCompatActivity {
buttonLogin.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
- // showLogPathInfo();
- showToastU_api_response_data();
+ // 显示自启动状态信息(调试功能)
+ showAutoStartStatusInfo();
return true;
}
});
+
+ // 添加双击测试功能
+ setupDoubleTapTest();
+ }
+
+ /**
+ * 设置双击测试功能
+ */
+ private void setupDoubleTapTest() {
+ final long[] taps = new long[3]; // 增加到3个点击点
+ final int[] tapCount = {0};
+
+ buttonLogin.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ long currentTime = System.currentTimeMillis();
+ taps[tapCount[0] % 3] = currentTime;
+ tapCount[0]++;
+
+ // 检查是否在300ms内三击
+ if (tapCount[0] >= 3 && (currentTime - taps[(tapCount[0] - 3) % 3]) < 300) {
+ // 三击触发直接启动测试
+ triggerDirectStartTest();
+ tapCount[0] = 0; // 重置计数
+ }
+ // 检查是否在300ms内双击
+ else if (tapCount[0] >= 2 && (currentTime - taps[(tapCount[0] - 2) % 3]) < 300) {
+ // 双击触发自启动测试
+ triggerAutoStartTest();
+ tapCount[0] = 0; // 重置计数
+ } else {
+ // 正常的登录按钮点击事件
+ handleLoginButtonClick();
+ }
+ }
+ });
+ }
+
+ /**
+ * 处理登录按钮点击事件
+ */
+ private void handleLoginButtonClick() {
+ String username = editTextUsername.getText().toString().trim();
+ String password = editTextPassword.getText().toString().trim();
+
+ // 在测试环境下,如果用户名和密码都为空,自动填充默认账号
+ if (isTestEnvironment() && username.isEmpty() && password.isEmpty()) {
+ username = "00167";
+ password = "123456";
+
+ // 更新输入框显示
+ editTextUsername.setText(username);
+ editTextPassword.setText(password);
+
+ // 显示提示信息
+ showToast("测试环境:已自动填充默认账号");
+
+ android.util.Log.d("MainActivity", "Test environment: Auto-filled default credentials");
+ }
+
+ if (validateInput(username, password)) {
+ performLogin(username, password);
+ }
+ }
+
+ /**
+ * 触发自启动测试
+ */
+ private void triggerAutoStartTest() {
+ try {
+ // 使用反射调用测试辅助类
+ Class> testHelperClass = Class.forName("com.ouxuan.oxface.utils.BootSimulationHelper");
+ java.lang.reflect.Method testMethod = testHelperClass.getMethod("simulateBootCompleted", android.content.Context.class);
+ testMethod.invoke(null, this);
+
+ showToast("自启动测试已触发");
+ } catch (Exception e) {
+ android.util.Log.e(TAG, "触发自启动测试失败", e);
+ showToast("触发自启动测试失败");
+ }
+ }
+
+ /**
+ * 直接启动应用测试
+ */
+ private void triggerDirectStartTest() {
+ try {
+ // 使用反射调用测试辅助类
+ Class> testHelperClass = Class.forName("com.ouxuan.oxface.utils.BootSimulationHelper");
+ java.lang.reflect.Method testMethod = testHelperClass.getMethod("directStartApp", android.content.Context.class);
+ testMethod.invoke(null, this);
+
+ showToast("直接启动测试已触发");
+ } catch (Exception e) {
+ android.util.Log.e(TAG, "触发直接启动测试失败", e);
+ showToast("触发直接启动测试失败");
+ }
}
/**
@@ -793,4 +938,38 @@ public class MainActivity extends AppCompatActivity {
// UtilCodeHelper.Toast.showShort(apiResponseDataJson);
}
+
+ /**
+ * 显示自启动状态信息(调试功能)
+ */
+ private void showAutoStartStatusInfo() {
+ if (autoStartManager != null) {
+ String statusInfo = autoStartManager.getAutoStartStatusInfo();
+ LogManager.logDebug(TAG, "自启动状态信息:\n" + statusInfo);
+
+ // 创建弹框显示详细状态
+ android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this);
+ builder.setTitle("自启动功能状态(调试)");
+ builder.setMessage(statusInfo);
+ builder.setPositiveButton("测试自启动", new android.content.DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(android.content.DialogInterface dialog, int which) {
+ // 执行自启动功能测试
+ autoStartManager.testAutoStartFunction();
+ showToast("自启动测试已执行,请查看日志");
+ }
+ });
+ builder.setNegativeButton("关闭", null);
+ builder.setNeutralButton("重置统计", new android.content.DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(android.content.DialogInterface dialog, int which) {
+ autoStartManager.resetAutoStartStats();
+ showToast("自启动统计信息已重置");
+ }
+ });
+ builder.show();
+ } else {
+ showToast("自启动管理器未初始化");
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/debug/AlarmTestActivity.java b/app/src/main/java/com/ouxuan/oxface/debug/AlarmTestActivity.java
new file mode 100644
index 0000000..489bf36
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/debug/AlarmTestActivity.java
@@ -0,0 +1,257 @@
+package com.ouxuan.oxface.debug;
+
+import android.app.Activity;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.ouxuan.oxface.receiver.AlarmReceiver;
+import com.ouxuan.oxface.utils.AutoStartManager;
+
+/**
+ * 闹钟机制测试Activity
+ */
+public class AlarmTestActivity extends Activity {
+
+ private static final String TAG = "AlarmTest";
+ private TextView textViewLog;
+ private ScrollView scrollViewLog;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // 创建测试界面
+ createTestLayout();
+
+ Log.i(TAG, "闹钟机制测试Activity已启动");
+ appendLog("闹钟机制测试Activity已启动");
+ }
+
+ private void createTestLayout() {
+ // 创建垂直布局
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.setPadding(50, 50, 50, 50);
+
+ // 标题
+ TextView title = new TextView(this);
+ title.setText("闹钟机制测试");
+ title.setTextSize(18);
+ title.setPadding(0, 0, 0, 30);
+ layout.addView(title);
+
+ // 测试按钮1:设置闹钟
+ Button btnSetAlarm = new Button(this);
+ btnSetAlarm.setText("设置闹钟(5秒后)");
+ btnSetAlarm.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testSetAlarm();
+ }
+ });
+ layout.addView(btnSetAlarm);
+
+ // 测试按钮2:立即触发闹钟
+ Button btnTriggerAlarm = new Button(this);
+ btnTriggerAlarm.setText("立即触发闹钟");
+ btnTriggerAlarm.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testTriggerAlarm();
+ }
+ });
+ layout.addView(btnTriggerAlarm);
+
+ // 测试按钮3:检查自启动状态
+ Button btnCheckStatus = new Button(this);
+ btnCheckStatus.setText("检查自启动状态");
+ btnCheckStatus.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ checkAutoStartStatus();
+ }
+ });
+ layout.addView(btnCheckStatus);
+
+ // 测试按钮4:测试BootReceiver
+ Button btnTestBootReceiver = new Button(this);
+ btnTestBootReceiver.setText("测试BootReceiver");
+ btnTestBootReceiver.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testBootReceiver();
+ }
+ });
+ layout.addView(btnTestBootReceiver);
+
+ // 测试按钮5:检查AlarmManager状态
+ Button btnCheckAlarmManager = new Button(this);
+ btnCheckAlarmManager.setText("检查AlarmManager状态");
+ btnCheckAlarmManager.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ checkAlarmManagerStatus();
+ }
+ });
+ layout.addView(btnCheckAlarmManager);
+
+ // 日志显示区域
+ scrollViewLog = new ScrollView(this);
+ textViewLog = new TextView(this);
+ textViewLog.setText("日志输出区域:\n");
+ scrollViewLog.addView(textViewLog);
+ layout.addView(scrollViewLog);
+
+ setContentView(layout);
+ }
+
+ private void testSetAlarm() {
+ appendLog("=== 设置闹钟测试 ===");
+ try {
+ // 获取AlarmManager
+ AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+
+ // 创建闹钟PendingIntent
+ android.app.PendingIntent pendingIntent = AlarmReceiver.createAlarmPendingIntent(
+ this,
+ true,
+ "alarm_test",
+ System.currentTimeMillis()
+ );
+
+ long triggerTime = System.currentTimeMillis() + 5000; // 5秒后触发
+
+ // 设置闹钟
+ if (alarmManager != null) {
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+ alarmManager.setExactAndAllowWhileIdle(
+ AlarmManager.RTC_WAKEUP,
+ triggerTime,
+ pendingIntent
+ );
+ } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ alarmManager.setExact(
+ AlarmManager.RTC_WAKEUP,
+ triggerTime,
+ pendingIntent
+ );
+ } else {
+ alarmManager.set(
+ AlarmManager.RTC_WAKEUP,
+ triggerTime,
+ pendingIntent
+ );
+ }
+
+ appendLog("闹钟设置成功,将在5秒后触发");
+ Toast.makeText(this, "闹钟设置成功,将在5秒后触发", Toast.LENGTH_SHORT).show();
+ } else {
+ appendLog("AlarmManager不可用");
+ Toast.makeText(this, "AlarmManager不可用", Toast.LENGTH_SHORT).show();
+ }
+ } catch (Exception e) {
+ appendLog("设置闹钟失败: " + e.getMessage());
+ Log.e(TAG, "设置闹钟失败", e);
+ Toast.makeText(this, "设置闹钟失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void testTriggerAlarm() {
+ appendLog("=== 立即触发闹钟测试 ===");
+ try {
+ // 创建模拟的闹钟Intent
+ Intent alarmIntent = new Intent(this, AlarmReceiver.class);
+ alarmIntent.setAction(AlarmReceiver.ACTION_ALARM_TRIGGER);
+ alarmIntent.putExtra("auto_start", true);
+ alarmIntent.putExtra("boot_reason", "manual_test");
+ alarmIntent.putExtra("boot_time", System.currentTimeMillis());
+
+ // 直接调用AlarmReceiver
+ AlarmReceiver alarmReceiver = new AlarmReceiver();
+ alarmReceiver.onReceive(this, alarmIntent);
+
+ appendLog("闹钟触发完成");
+ Toast.makeText(this, "闹钟触发完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("触发闹钟失败: " + e.getMessage());
+ Log.e(TAG, "触发闹钟失败", e);
+ Toast.makeText(this, "触发闹钟失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void checkAutoStartStatus() {
+ appendLog("=== 自启动状态检查 ===");
+ try {
+ AutoStartManager autoStartManager = AutoStartManager.getInstance(this);
+ String statusInfo = autoStartManager.getAutoStartStatusInfo();
+ appendLog("自启动状态信息:\n" + statusInfo);
+
+ Toast.makeText(this, "状态检查完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("状态检查失败: " + e.getMessage());
+ Log.e(TAG, "状态检查失败", e);
+ Toast.makeText(this, "状态检查失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void testBootReceiver() {
+ appendLog("=== 测试BootReceiver ===");
+ try {
+ com.ouxuan.oxface.receiver.BootReceiver.testBootReceiver(this);
+ appendLog("BootReceiver测试完成");
+ Toast.makeText(this, "BootReceiver测试完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("BootReceiver测试失败: " + e.getMessage());
+ Log.e(TAG, "BootReceiver测试失败", e);
+ Toast.makeText(this, "BootReceiver测试失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void checkAlarmManagerStatus() {
+ appendLog("=== AlarmManager状态检查 ===");
+ try {
+ AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+ if (alarmManager != null) {
+ appendLog("AlarmManager可用");
+
+ // 检查是否支持精确闹钟
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+ appendLog("支持setExactAndAllowWhileIdle方法");
+ } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ appendLog("支持setExact方法");
+ } else {
+ appendLog("使用标准set方法");
+ }
+ } else {
+ appendLog("AlarmManager不可用");
+ }
+ } catch (Exception e) {
+ appendLog("AlarmManager状态检查失败: " + e.getMessage());
+ Log.e(TAG, "AlarmManager状态检查失败", e);
+ }
+ }
+
+ private void appendLog(String message) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ textViewLog.append(message + "\n");
+ scrollViewLog.post(new Runnable() {
+ @Override
+ public void run() {
+ scrollViewLog.smoothScrollBy(0, textViewLog.getHeight());
+ }
+ });
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/debug/AutoStartComprehensiveTestActivity.java b/app/src/main/java/com/ouxuan/oxface/debug/AutoStartComprehensiveTestActivity.java
new file mode 100644
index 0000000..3f91f33
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/debug/AutoStartComprehensiveTestActivity.java
@@ -0,0 +1,183 @@
+package com.ouxuan.oxface.debug;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.ouxuan.oxface.utils.AutoStartManager;
+import com.ouxuan.oxface.utils.BootSimulationHelper;
+import com.ouxuan.oxface.utils.ShellCommandManager;
+
+/**
+ * 自启动功能综合测试Activity
+ */
+public class AutoStartComprehensiveTestActivity extends Activity {
+
+ private static final String TAG = "AutoStartComprehensiveTest";
+ private TextView textViewLog;
+ private ScrollView scrollViewLog;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // 创建测试界面
+ createTestLayout();
+
+ Log.i(TAG, "自启动功能综合测试Activity已启动");
+ appendLog("自启动功能综合测试Activity已启动");
+ }
+
+ private void createTestLayout() {
+ // 创建垂直布局
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.setPadding(50, 50, 50, 50);
+
+ // 标题
+ TextView title = new TextView(this);
+ title.setText("自启动功能综合测试");
+ title.setTextSize(18);
+ title.setPadding(0, 0, 0, 30);
+ layout.addView(title);
+
+ // 测试按钮1:模拟系统启动
+ Button btnSimulateBoot = new Button(this);
+ btnSimulateBoot.setText("模拟系统启动");
+ btnSimulateBoot.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testSimulateBoot();
+ }
+ });
+ layout.addView(btnSimulateBoot);
+
+ // 测试按钮2:直接启动应用
+ Button btnDirectStart = new Button(this);
+ btnDirectStart.setText("直接启动应用");
+ btnDirectStart.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testDirectStart();
+ }
+ });
+ layout.addView(btnDirectStart);
+
+ // 测试按钮3:测试Shell命令
+ Button btnTestShell = new Button(this);
+ btnTestShell.setText("测试Shell命令");
+ btnTestShell.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testShellCommands();
+ }
+ });
+ layout.addView(btnTestShell);
+
+ // 测试按钮4:检查自启动状态
+ Button btnCheckStatus = new Button(this);
+ btnCheckStatus.setText("检查自启动状态");
+ btnCheckStatus.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ checkAutoStartStatus();
+ }
+ });
+ layout.addView(btnCheckStatus);
+
+ // 日志显示区域
+ scrollViewLog = new ScrollView(this);
+ textViewLog = new TextView(this);
+ textViewLog.setText("日志输出区域:\n");
+ scrollViewLog.addView(textViewLog);
+ layout.addView(scrollViewLog);
+
+ setContentView(layout);
+ }
+
+ private void testSimulateBoot() {
+ appendLog("=== 模拟系统启动测试 ===");
+ try {
+ BootSimulationHelper.simulateBootCompleted(this);
+ appendLog("模拟系统启动完成");
+ Toast.makeText(this, "模拟系统启动完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("模拟系统启动失败: " + e.getMessage());
+ Log.e(TAG, "模拟系统启动失败", e);
+ Toast.makeText(this, "模拟系统启动失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void testDirectStart() {
+ appendLog("=== 直接启动应用测试 ===");
+ try {
+ BootSimulationHelper.directStartApp(this);
+ appendLog("直接启动应用完成");
+ Toast.makeText(this, "直接启动应用完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("直接启动应用失败: " + e.getMessage());
+ Log.e(TAG, "直接启动应用失败", e);
+ Toast.makeText(this, "直接启动应用失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void testShellCommands() {
+ appendLog("=== Shell命令测试 ===");
+ try {
+ ShellCommandManager shellManager = ShellCommandManager.getInstance(this);
+
+ // 检查ADB可用性
+ boolean adbAvailable = shellManager.isAdbAvailable();
+ appendLog("ADB可用性: " + (adbAvailable ? "可用" : "不可用"));
+
+ if (adbAvailable) {
+ // 测试启动应用
+ boolean result = shellManager.startCurrentApp("shell_test");
+ appendLog("Shell启动应用: " + (result ? "成功" : "失败"));
+ }
+
+ Toast.makeText(this, "Shell命令测试完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("Shell命令测试失败: " + e.getMessage());
+ Log.e(TAG, "Shell命令测试失败", e);
+ Toast.makeText(this, "Shell命令测试失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void checkAutoStartStatus() {
+ appendLog("=== 自启动状态检查 ===");
+ try {
+ AutoStartManager autoStartManager = AutoStartManager.getInstance(this);
+ String statusInfo = autoStartManager.getAutoStartStatusInfo();
+ appendLog("自启动状态信息:\n" + statusInfo);
+
+ Toast.makeText(this, "状态检查完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("状态检查失败: " + e.getMessage());
+ Log.e(TAG, "状态检查失败", e);
+ Toast.makeText(this, "状态检查失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void appendLog(String message) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ textViewLog.append(message + "\n");
+ scrollViewLog.post(new Runnable() {
+ @Override
+ public void run() {
+ scrollViewLog.smoothScrollBy(0, textViewLog.getHeight());
+ }
+ });
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/debug/DirectBootTestActivity.java b/app/src/main/java/com/ouxuan/oxface/debug/DirectBootTestActivity.java
new file mode 100644
index 0000000..35bc5bd
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/debug/DirectBootTestActivity.java
@@ -0,0 +1,162 @@
+package com.ouxuan.oxface.debug;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.ouxuan.oxface.receiver.BootReceiver;
+import com.ouxuan.oxface.utils.AutoStartManager;
+
+/**
+ * 直接测试BootReceiver的Activity
+ */
+public class DirectBootTestActivity extends Activity {
+
+ private static final String TAG = "DirectBootTest";
+ private TextView textViewLog;
+ private ScrollView scrollViewLog;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // 创建测试界面
+ createTestLayout();
+
+ Log.i(TAG, "直接BootReceiver测试Activity已启动");
+ appendLog("直接BootReceiver测试Activity已启动");
+ }
+
+ private void createTestLayout() {
+ // 创建垂直布局
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.setPadding(50, 50, 50, 50);
+
+ // 标题
+ TextView title = new TextView(this);
+ title.setText("直接BootReceiver测试");
+ title.setTextSize(18);
+ title.setPadding(0, 0, 0, 30);
+ layout.addView(title);
+
+ // 测试按钮1:直接调用BootReceiver
+ Button btnDirectBoot = new Button(this);
+ btnDirectBoot.setText("直接调用BootReceiver");
+ btnDirectBoot.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testDirectBootReceiver();
+ }
+ });
+ layout.addView(btnDirectBoot);
+
+ // 测试按钮2:测试AlarmManager
+ Button btnTestAlarm = new Button(this);
+ btnTestAlarm.setText("测试AlarmManager");
+ btnTestAlarm.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testAlarmManager();
+ }
+ });
+ layout.addView(btnTestAlarm);
+
+ // 测试按钮3:检查自启动状态
+ Button btnCheckStatus = new Button(this);
+ btnCheckStatus.setText("检查自启动状态");
+ btnCheckStatus.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ checkAutoStartStatus();
+ }
+ });
+ layout.addView(btnCheckStatus);
+
+ // 日志显示区域
+ scrollViewLog = new ScrollView(this);
+ textViewLog = new TextView(this);
+ textViewLog.setText("日志输出区域:\n");
+ scrollViewLog.addView(textViewLog);
+ layout.addView(scrollViewLog);
+
+ setContentView(layout);
+ }
+
+ private void testDirectBootReceiver() {
+ appendLog("=== 直接调用BootReceiver测试 ===");
+ try {
+ // 创建模拟的启动完成Intent
+ Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED);
+ bootIntent.putExtra("direct_test", true);
+ bootIntent.putExtra("test_time", System.currentTimeMillis());
+
+ // 直接调用BootReceiver的onReceive方法
+ BootReceiver bootReceiver = new BootReceiver();
+ bootReceiver.onReceive(this, bootIntent);
+
+ appendLog("直接调用BootReceiver完成");
+ Toast.makeText(this, "直接调用BootReceiver完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("直接调用BootReceiver失败: " + e.getMessage());
+ Log.e(TAG, "直接调用BootReceiver失败", e);
+ Toast.makeText(this, "直接调用BootReceiver失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void testAlarmManager() {
+ appendLog("=== 测试AlarmManager ===");
+ try {
+ // 直接调用BootReceiver中的handleBootCompleted方法
+ BootReceiver bootReceiver = new BootReceiver();
+ // 使用反射调用私有方法
+ java.lang.reflect.Method method = BootReceiver.class.getDeclaredMethod("handleBootCompleted", android.content.Context.class);
+ method.setAccessible(true);
+ method.invoke(bootReceiver, this);
+
+ appendLog("AlarmManager测试完成");
+ Toast.makeText(this, "AlarmManager测试完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("AlarmManager测试失败: " + e.getMessage());
+ Log.e(TAG, "AlarmManager测试失败", e);
+ Toast.makeText(this, "AlarmManager测试失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void checkAutoStartStatus() {
+ appendLog("=== 自启动状态检查 ===");
+ try {
+ AutoStartManager autoStartManager = AutoStartManager.getInstance(this);
+ String statusInfo = autoStartManager.getAutoStartStatusInfo();
+ appendLog("自启动状态信息:\n" + statusInfo);
+
+ Toast.makeText(this, "状态检查完成", Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {
+ appendLog("状态检查失败: " + e.getMessage());
+ Log.e(TAG, "状态检查失败", e);
+ Toast.makeText(this, "状态检查失败", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void appendLog(String message) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ textViewLog.append(message + "\n");
+ scrollViewLog.post(new Runnable() {
+ @Override
+ public void run() {
+ scrollViewLog.smoothScrollBy(0, textViewLog.getHeight());
+ }
+ });
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/debug/ShellTestActivity.java b/app/src/main/java/com/ouxuan/oxface/debug/ShellTestActivity.java
new file mode 100644
index 0000000..5ac69a6
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/debug/ShellTestActivity.java
@@ -0,0 +1,130 @@
+package com.ouxuan.oxface.debug;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.ouxuan.oxface.utils.ShellCommandManager;
+
+/**
+ * Shell命令功能测试Activity
+ */
+public class ShellTestActivity extends Activity {
+
+ private static final String TAG = "ShellTestActivity";
+ private TextView textViewLog;
+ private ScrollView scrollViewLog;
+ private ShellCommandManager shellCommandManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // 创建测试界面
+ createTestLayout();
+
+ // 初始化Shell命令管理器
+ shellCommandManager = ShellCommandManager.getInstance(this);
+
+ Log.i(TAG, "Shell命令测试Activity已启动");
+ appendLog("Shell命令测试Activity已启动");
+ }
+
+ private void createTestLayout() {
+ // 创建垂直布局
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.setPadding(50, 50, 50, 50);
+
+ // 标题
+ TextView title = new TextView(this);
+ title.setText("Shell命令功能测试");
+ title.setTextSize(18);
+ title.setPadding(0, 0, 0, 30);
+ layout.addView(title);
+
+ // 测试按钮1:检查ADB可用性
+ Button btnCheckAdb = new Button(this);
+ btnCheckAdb.setText("检查ADB可用性");
+ btnCheckAdb.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testAdbAvailability();
+ }
+ });
+ layout.addView(btnCheckAdb);
+
+ // 测试按钮2:测试Shell能力
+ Button btnTestShell = new Button(this);
+ btnTestShell.setText("测试Shell能力");
+ btnTestShell.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testShellCapability();
+ }
+ });
+ layout.addView(btnTestShell);
+
+ // 测试按钮3:启动应用测试
+ Button btnStartApp = new Button(this);
+ btnStartApp.setText("启动应用测试");
+ btnStartApp.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ testStartApp();
+ }
+ });
+ layout.addView(btnStartApp);
+
+ // 日志显示区域
+ scrollViewLog = new ScrollView(this);
+ textViewLog = new TextView(this);
+ textViewLog.setText("日志输出区域:\n");
+ scrollViewLog.addView(textViewLog);
+ layout.addView(scrollViewLog);
+
+ setContentView(layout);
+ }
+
+ private void testAdbAvailability() {
+ appendLog("=== 检查ADB可用性 ===");
+ boolean available = shellCommandManager.isAdbAvailable();
+ appendLog("ADB可用性: " + (available ? "可用" : "不可用"));
+ Toast.makeText(this, "ADB可用性: " + (available ? "可用" : "不可用"), Toast.LENGTH_SHORT).show();
+ }
+
+ private void testShellCapability() {
+ appendLog("=== 测试Shell能力 ===");
+ String capabilityInfo = shellCommandManager.getShellCapabilityInfo();
+ appendLog(capabilityInfo);
+ Toast.makeText(this, "Shell能力测试完成", Toast.LENGTH_SHORT).show();
+ }
+
+ private void testStartApp() {
+ appendLog("=== 启动应用测试 ===");
+ boolean result = shellCommandManager.startCurrentApp("shell_test");
+ appendLog("启动结果: " + (result ? "成功" : "失败"));
+ Toast.makeText(this, "启动测试: " + (result ? "成功" : "失败"), Toast.LENGTH_SHORT).show();
+ }
+
+ private void appendLog(String message) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ textViewLog.append(message + "\n");
+ scrollViewLog.post(new Runnable() {
+ @Override
+ public void run() {
+ scrollViewLog.smoothScrollBy(0, textViewLog.getHeight());
+ }
+ });
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/receiver/AlarmReceiver.java b/app/src/main/java/com/ouxuan/oxface/receiver/AlarmReceiver.java
new file mode 100644
index 0000000..4d1f76f
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/receiver/AlarmReceiver.java
@@ -0,0 +1,114 @@
+package com.ouxuan.oxface.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import com.ouxuan.oxface.MainActivity;
+import com.ouxuan.oxface.utils.LogManager;
+
+/**
+ * 闹钟广播接收器
+ * 用于处理AlarmManager触发的延迟启动
+ */
+public class AlarmReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "AlarmReceiver";
+ public static final String ACTION_ALARM_TRIGGER = "com.ouxuan.oxface.ALARM_TRIGGER";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null || intent.getAction() == null) {
+ Log.w(TAG, "接收到空的Intent或Action");
+ return;
+ }
+
+ String action = intent.getAction();
+ Log.i(TAG, "接收到闹钟广播: " + action);
+ LogManager.logOperation(TAG, "接收到闹钟广播: " + action);
+
+ if (ACTION_ALARM_TRIGGER.equals(action)) {
+ handleAlarmTrigger(context, intent);
+ } else {
+ Log.w(TAG, "未处理的广播事件: " + action);
+ }
+ }
+
+ /**
+ * 处理闹钟触发事件
+ * @param context 上下文
+ * @param intent Intent
+ */
+ private void handleAlarmTrigger(Context context, Intent intent) {
+ try {
+ Log.i(TAG, "闹钟触发,开始启动应用");
+ LogManager.logOperation(TAG, "闹钟触发,开始启动应用");
+
+ // 获取启动参数
+ boolean isAutoStart = intent.getBooleanExtra("auto_start", false);
+ String bootReason = intent.getStringExtra("boot_reason");
+ long bootTime = intent.getLongExtra("boot_time", 0);
+
+ Log.i(TAG, "启动参数 - 自启动: " + isAutoStart + ", 启动原因: " + bootReason + ", 启动时间: " + bootTime);
+
+ // 启动主活动
+ Intent launchIntent = new Intent(context, MainActivity.class);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
+ // 添加自启动标识
+ launchIntent.putExtra("auto_start", isAutoStart);
+ launchIntent.putExtra("boot_reason", bootReason);
+ launchIntent.putExtra("boot_time", bootTime);
+
+// context.startActivity(launchIntent);
+
+ new BootReceiver().startMainActivity(context);
+
+ Log.i(TAG, "应用启动成功");
+ LogManager.logOperation(TAG, "应用启动成功,恢复24小时无人值守模式");
+
+ } catch (Exception e) {
+ Log.e(TAG, "处理闹钟触发事件失败", e);
+ LogManager.logError(TAG, "处理闹钟触发事件失败", e);
+
+ // 备用方案:尝试通过服务启动
+ try {
+ Intent serviceIntent = new Intent(context, AutoStartService.class);
+ serviceIntent.putExtra("start_reason", "alarm_fallback");
+ serviceIntent.putExtra("boot_time", System.currentTimeMillis());
+ context.startForegroundService(serviceIntent);
+ Log.i(TAG, "通过服务启动应用");
+ LogManager.logOperation(TAG, "通过服务启动应用");
+ } catch (Exception serviceError) {
+ Log.e(TAG, "通过服务启动也失败", serviceError);
+ LogManager.logError(TAG, "通过服务启动也失败", serviceError);
+ }
+ }
+ }
+
+ /**
+ * 创建闹钟PendingIntent
+ * @param context 上下文
+ * @param isAutoStart 是否为自启动
+ * @param bootReason 启动原因
+ * @param bootTime 启动时间
+ * @return PendingIntent
+ */
+ public static android.app.PendingIntent createAlarmPendingIntent(Context context, boolean isAutoStart, String bootReason, long bootTime) {
+ Intent alarmIntent = new Intent(context, AlarmReceiver.class);
+ alarmIntent.setAction(ACTION_ALARM_TRIGGER);
+ alarmIntent.putExtra("auto_start", isAutoStart);
+ alarmIntent.putExtra("boot_reason", bootReason);
+ alarmIntent.putExtra("boot_time", bootTime);
+
+ return android.app.PendingIntent.getBroadcast(
+ context,
+ 0,
+ alarmIntent,
+ android.app.PendingIntent.FLAG_UPDATE_CURRENT | android.app.PendingIntent.FLAG_IMMUTABLE
+ );
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/receiver/AutoStartService.java b/app/src/main/java/com/ouxuan/oxface/receiver/AutoStartService.java
new file mode 100644
index 0000000..7c328e7
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/receiver/AutoStartService.java
@@ -0,0 +1,185 @@
+package com.ouxuan.oxface.receiver;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.util.Log;
+
+import androidx.core.app.NotificationCompat;
+
+import com.ouxuan.oxface.MainActivity;
+import com.ouxuan.oxface.R;
+import com.ouxuan.oxface.utils.LogManager;
+import com.ouxuan.oxface.utils.ShellCommandManager;
+
+/**
+ * 自动启动服务
+ * 用于在应用无法直接启动时,通过服务的方式启动主界面
+ * 支持前台服务,确保在Android高版本中正常运行
+ */
+public class AutoStartService extends Service {
+
+ private static final String TAG = "AutoStartService";
+ private static final String CHANNEL_ID = "auto_start_channel";
+ private static final int NOTIFICATION_ID = 1001;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i(TAG, "AutoStartService创建");
+ LogManager.logOperation(TAG, "自动启动服务已创建");
+
+ // 创建通知渠道
+ createNotificationChannel();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.i(TAG, "AutoStartService启动");
+ LogManager.logOperation(TAG, "自动启动服务开始执行");
+
+ // 启动前台服务
+ startForeground(NOTIFICATION_ID, createNotification());
+
+ // 延迟启动主界面
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ launchMainActivity();
+ // 启动完成后停止服务
+ stopSelf();
+ }
+ }, 3000); // 延迟3秒
+
+ // 返回START_STICKY,确保服务被系统杀死后会重新启动
+ return START_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.i(TAG, "AutoStartService销毁");
+ LogManager.logOperation(TAG, "自动启动服务已停止");
+ }
+
+ /**
+ * 创建通知渠道(Android 8.0及以上版本需要)
+ */
+ private void createNotificationChannel() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationChannel channel = new NotificationChannel(
+ CHANNEL_ID,
+ "自动启动服务",
+ NotificationManager.IMPORTANCE_LOW
+ );
+ channel.setDescription("用于24小时无人值守应用自动启动");
+ channel.setShowBadge(false);
+ channel.setSound(null, null);
+ channel.enableVibration(false);
+
+ NotificationManager manager = getSystemService(NotificationManager.class);
+ if (manager != null) {
+ manager.createNotificationChannel(channel);
+ }
+ }
+ }
+
+ /**
+ * 创建前台服务通知
+ */
+ private Notification createNotification() {
+ Intent notificationIntent = new Intent(this, MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ this,
+ 0,
+ notificationIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
+ );
+
+ return new NotificationCompat.Builder(this, CHANNEL_ID)
+ .setContentTitle("应用自动启动中...")
+ .setContentText("正在恢复24小时无人值守模式")
+ .setSmallIcon(R.mipmap.ic_launcher)
+ .setContentIntent(pendingIntent)
+ .setPriority(NotificationCompat.PRIORITY_LOW)
+ .setOngoing(true)
+ .setSilent(true)
+ .build();
+ }
+
+ /**
+ * 启动主界面
+ */
+ private void launchMainActivity() {
+ try {
+ Log.i(TAG, "开始启动主界面");
+
+ // 方式1: 优先尝试Shell命令启动(推荐方式)
+ ShellCommandManager shellManager = ShellCommandManager.getInstance(this);
+ if (shellManager.isAdbAvailable()) {
+ Log.i(TAG, "使用Shell命令启动主界面");
+ boolean shellResult = shellManager.startCurrentApp("service_start");
+
+ if (shellResult) {
+ Log.i(TAG, "Shell命令启动主界面成功");
+ LogManager.logOperation(TAG, "Shell命令启动主界面成功");
+ return; // 成功启动,直接返回
+ } else {
+ Log.w(TAG, "Shell命令启动失败,尝试备用方式");
+ }
+ } else {
+ Log.w(TAG, "Shell命令不可用,使用传统启动方式");
+ }
+
+ // 方式2: 备用的传统 Intent 启动方式
+ Intent launchIntent = new Intent(this, MainActivity.class);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
+ // 添加自启动标识
+ launchIntent.putExtra("auto_start", true);
+ launchIntent.putExtra("start_source", "service");
+ launchIntent.putExtra("service_start_time", System.currentTimeMillis());
+ launchIntent.putExtra("start_method", "intent_fallback");
+
+ startActivity(launchIntent);
+
+ Log.i(TAG, "传统Intent方式启动主界面完成");
+ LogManager.logOperation(TAG, "传统Intent方式启动主界面成功");
+
+ } catch (Exception e) {
+ Log.e(TAG, "通过服务启动主界面失败", e);
+ LogManager.logError(TAG, "服务启动主界面失败", e);
+
+ // 最后的备用方案
+ try {
+ Intent finalIntent = new Intent(this, MainActivity.class);
+ finalIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ finalIntent.putExtra("auto_start", true);
+ finalIntent.putExtra("start_source", "service_final_fallback");
+ finalIntent.putExtra("service_start_time", System.currentTimeMillis());
+ startActivity(finalIntent);
+ Log.i(TAG, "最终备用方案启动成功");
+ LogManager.logOperation(TAG, "最终备用方案启动成功");
+ } catch (Exception finalException) {
+ Log.e(TAG, "所有启动方式都失败", finalException);
+ LogManager.logError(TAG, "所有启动方式都失败", finalException);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/receiver/BootReceiver.java b/app/src/main/java/com/ouxuan/oxface/receiver/BootReceiver.java
new file mode 100644
index 0000000..1087919
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/receiver/BootReceiver.java
@@ -0,0 +1,227 @@
+package com.ouxuan.oxface.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+
+import com.ouxuan.oxface.MainActivity;
+import com.ouxuan.oxface.utils.AutoStartManager;
+import com.ouxuan.oxface.utils.LogManager;
+import com.ouxuan.oxface.utils.ShellCommandManager;
+
+/**
+ * 系统启动完成广播接收器
+ * 用于在设备重启后自动启动应用
+ * 支持24小时无人值守运营管理
+ */
+public class BootReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "BootReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null || intent.getAction() == null) {
+ Log.w(TAG, "接收到空的Intent或Action");
+ return;
+ }
+
+ String action = intent.getAction();
+ Log.i(TAG, "接收到广播: " + action);
+ LogManager.logOperation(TAG, "接收到系统广播: " + action);
+
+ // 记录设备信息
+ Log.i(TAG, "设备信息 - 厂商: " + android.os.Build.MANUFACTURER +
+ ", 型号: " + android.os.Build.MODEL +
+ ", Android版本: " + android.os.Build.VERSION.RELEASE);
+
+ // 处理系统启动完成事件
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action) ||
+ "android.intent.action.QUICKBOOT_POWERON".equals(action) ||
+ "android.intent.action.REBOOT".equals(action)) {
+
+ Log.i(TAG, "匹配到系统启动事件,开始处理");
+ handleBootCompleted(context);
+ } else {
+ Log.w(TAG, "未处理的广播事件: " + action);
+ }
+ }
+
+ /**
+ * 处理系统启动完成事件
+ * @param context 上下文
+ */
+ private void handleBootCompleted(Context context) {
+ try {
+ Log.i(TAG, "系统启动完成,准备自动启动应用");
+ LogManager.logOperation(TAG, "检测到系统重启,开始自动启动流程");
+
+ // 记录启动时间
+ com.ouxuan.oxface.utils.AutoStartManager autoStartManager = com.ouxuan.oxface.utils.AutoStartManager.getInstance(context);
+ autoStartManager.recordBootTime();
+
+ // 使用AlarmManager实现延迟启动,确保在系统完全启动后执行
+ android.app.AlarmManager alarmManager = (android.app.AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+ // 创建闹钟PendingIntent
+ android.app.PendingIntent pendingIntent = com.ouxuan.oxface.receiver.AlarmReceiver.createAlarmPendingIntent(
+ context,
+ true,
+ "system_reboot",
+ System.currentTimeMillis()
+ );
+
+ long triggerTime = System.currentTimeMillis() + 5000; // 5秒后启动
+
+ // 使用更可靠的闹钟类型
+ if (alarmManager != null) {
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+ // Android 6.0+ 使用精确闹钟
+ alarmManager.setExactAndAllowWhileIdle(
+ android.app.AlarmManager.RTC_WAKEUP,
+ triggerTime,
+ pendingIntent
+ );
+ } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ // Android 4.4+ 使用setExact
+ alarmManager.setExact(
+ android.app.AlarmManager.RTC_WAKEUP,
+ triggerTime,
+ pendingIntent
+ );
+ } else {
+ // 旧版本使用标准闹钟
+ alarmManager.set(
+ android.app.AlarmManager.RTC_WAKEUP,
+ triggerTime,
+ pendingIntent
+ );
+ }
+
+ Log.i(TAG, "已设置延迟启动闹钟,将在5秒后启动应用");
+ LogManager.logOperation(TAG, "已设置延迟启动闹钟,将在5秒后启动应用,使用精确闹钟");
+ } else {
+ // 如果AlarmManager不可用,直接启动
+ Log.w(TAG, "AlarmManager不可用,立即启动应用");
+ LogManager.logWarning(TAG, "AlarmManager不可用,立即启动应用");
+ startMainActivity(context);
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, "处理系统启动完成事件失败", e);
+ LogManager.logError(TAG, "自动启动失败", e);
+
+ // 出现异常时尝试直接启动
+ try {
+ startMainActivity(context);
+ } catch (Exception fallbackException) {
+ Log.e(TAG, "备用启动方式也失败", fallbackException);
+ LogManager.logError(TAG, "备用启动方式也失败", fallbackException);
+ }
+ }
+ }
+
+ /**
+ * 启动主活动
+ * @param context 上下文
+ */
+ public void startMainActivity(Context context) {
+ try {
+ Log.i(TAG, "开始启动主活动");
+
+ // 方式1: 优先尝试Shell命令启动(推荐方式)
+ ShellCommandManager shellManager = ShellCommandManager.getInstance(context);
+ if (shellManager.isAdbAvailable()) {
+ Log.i(TAG, "使用Shell命令启动主活动");
+ boolean shellResult = shellManager.startCurrentApp("system_reboot");
+
+ if (shellResult) {
+ Log.i(TAG, "Shell命令启动主活动成功");
+ LogManager.logOperation(TAG, "Shell命令启动主活动成功,恢复24小时无人值守模式");
+ return; // 成功启动,直接返回
+ } else {
+ Log.w(TAG, "Shell命令启动失败,尝试备用方式");
+ }
+ } else {
+ Log.w(TAG, "Shell命令不可用,使用传统启动方式");
+ }
+
+ // 方式2: 备用的传统 Intent 启动方式
+ Intent launchIntent = new Intent(context, MainActivity.class);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
+ // 添加自启动标识
+ launchIntent.putExtra("auto_start", true);
+ launchIntent.putExtra("boot_reason", "system_reboot");
+ launchIntent.putExtra("boot_time", System.currentTimeMillis());
+ launchIntent.putExtra("start_method", "intent_fallback");
+
+ context.startActivity(launchIntent);
+
+ Log.i(TAG, "传统Intent方式启动主活动完成");
+ LogManager.logOperation(TAG, "传统Intent方式启动主活动成功,恢复24小时无人值守模式");
+
+ } catch (Exception e) {
+ Log.e(TAG, "启动主活动失败", e);
+ LogManager.logError(TAG, "启动主活动失败", e);
+
+ // 如果所有方式都失败,尝试通过服务启动
+ try {
+ Intent serviceIntent = new Intent(context, AutoStartService.class);
+ serviceIntent.putExtra("start_reason", "boot_receiver_fallback");
+ serviceIntent.putExtra("boot_time", System.currentTimeMillis());
+ context.startForegroundService(serviceIntent);
+ Log.i(TAG, "通过服务启动应用");
+ LogManager.logOperation(TAG, "通过服务启动应用");
+ } catch (Exception serviceError) {
+ Log.e(TAG, "通过服务启动也失败", serviceError);
+ LogManager.logError(TAG, "通过服务启动也失败", serviceError);
+
+ // 最后的备用方案
+ try {
+ Intent finalIntent = new Intent(context, MainActivity.class);
+ finalIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ finalIntent.putExtra("auto_start", true);
+ finalIntent.putExtra("boot_reason", "final_fallback");
+ finalIntent.putExtra("boot_time", System.currentTimeMillis());
+ context.startActivity(finalIntent);
+ Log.i(TAG, "最终备用方案启动成功");
+ LogManager.logOperation(TAG, "最终备用方案启动成功");
+ } catch (Exception finalException) {
+ Log.e(TAG, "所有启动方式都失败", finalException);
+ LogManager.logError(TAG, "所有启动方式都失败", finalException);
+ }
+ }
+ }
+ }
+
+ /**
+ * 手动测试广播接收器(用于调试)
+ * @param context 上下文
+ */
+ public static void testBootReceiver(Context context) {
+ Log.i(TAG, "=== 开始测试广播接收器 ===");
+ LogManager.logOperation(TAG, "手动测试广播接收器");
+
+ try {
+ BootReceiver receiver = new BootReceiver();
+ Intent testIntent = new Intent(Intent.ACTION_BOOT_COMPLETED);
+ testIntent.putExtra("test_mode", true);
+
+ receiver.onReceive(context, testIntent);
+
+ Log.i(TAG, "测试广播发送完成");
+ LogManager.logOperation(TAG, "测试广播发送完成");
+
+ } catch (Exception e) {
+ Log.e(TAG, "测试广播接收器失败", e);
+ LogManager.logError(TAG, "测试广播接收器失败", e);
+ }
+
+ Log.i(TAG, "=== 广播接收器测试完成 ===");
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/utils/AutoStartManager.java b/app/src/main/java/com/ouxuan/oxface/utils/AutoStartManager.java
new file mode 100644
index 0000000..9045dd0
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/utils/AutoStartManager.java
@@ -0,0 +1,354 @@
+package com.ouxuan.oxface.utils;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Build;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.ouxuan.oxface.receiver.AutoStartService;
+import com.ouxuan.oxface.utils.ShellCommandManager;
+
+/**
+ * 自动启动管理器
+ * 统一管理应用的自动启动功能
+ * 支持24小时无人值守运营管理
+ */
+public class AutoStartManager {
+
+ private static final String TAG = "AutoStartManager";
+ private static final String PREFS_NAME = "auto_start_prefs";
+ private static final String KEY_AUTO_START_ENABLED = "auto_start_enabled";
+ private static final String KEY_LAST_BOOT_TIME = "last_boot_time";
+ private static final String KEY_AUTO_START_COUNT = "auto_start_count";
+
+ private static volatile AutoStartManager instance;
+ private Context context;
+ private SharedPreferences preferences;
+ private ShellCommandManager shellCommandManager;
+
+ private AutoStartManager(Context context) {
+ this.context = context.getApplicationContext();
+ this.preferences = this.context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+ this.shellCommandManager = ShellCommandManager.getInstance(this.context);
+ }
+
+ /**
+ * 获取AutoStartManager单例实例
+ * @param context 上下文
+ * @return AutoStartManager实例
+ */
+ public static AutoStartManager getInstance(Context context) {
+ if (instance == null) {
+ synchronized (AutoStartManager.class) {
+ if (instance == null) {
+ instance = new AutoStartManager(context);
+ }
+ }
+ }
+ return instance;
+ }
+
+ /**
+ * 检查并请求自启动权限
+ * @return true 如果已有权限或请求成功
+ */
+ public boolean checkAndRequestAutoStartPermission() {
+ try {
+ // 检查电池优化白名单
+ if (!isIgnoringBatteryOptimizations()) {
+ requestIgnoreBatteryOptimizations();
+ }
+
+ // 检查自启动权限(主要针对国产手机)
+ if (!hasAutoStartPermission()) {
+ Log.i(TAG, "缺少自启动权限,建议用户手动开启");
+ LogManager.logWarning(TAG, "检测到可能缺少自启动权限,建议在系统设置中开启");
+ return false;
+ }
+
+ // 启用自动启动功能
+ setAutoStartEnabled(true);
+ LogManager.logOperation(TAG, "自动启动权限检查完成,功能已启用");
+ return true;
+
+ } catch (Exception e) {
+ Log.e(TAG, "检查自启动权限失败", e);
+ LogManager.logError(TAG, "检查自启动权限失败", e);
+ return false;
+ }
+ }
+
+ /**
+ * 检查是否在电池优化白名单中
+ */
+ private boolean isIgnoringBatteryOptimizations() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ return powerManager != null && powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
+ }
+ return true; // 低版本默认返回true
+ }
+
+ /**
+ * 请求忽略电池优化
+ */
+ private void requestIgnoreBatteryOptimizations() {
+ try {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+ intent.setData(Uri.parse("package:" + context.getPackageName()));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+
+ Log.i(TAG, "已请求电池优化白名单权限");
+ LogManager.logOperation(TAG, "已请求电池优化白名单权限");
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "请求电池优化白名单失败", e);
+ LogManager.logWarning(TAG, "请求电池优化白名单失败");
+ }
+ }
+
+ /**
+ * 检查是否有自启动权限(增强检测)
+ * 注意:不同厂商的自启动权限检测方式不同,这里提供基础检测
+ */
+ private boolean hasAutoStartPermission() {
+ // 基础检测:检查是否在电池优化白名单中
+ boolean hasBasicPermission = isIgnoringBatteryOptimizations();
+
+ // 检查厂商信息
+ String manufacturer = Build.MANUFACTURER.toLowerCase();
+ String model = Build.MODEL.toLowerCase();
+
+ Log.i(TAG, "设备信息 - 厂商: " + manufacturer + ", 型号: " + model + ", Android版本: " + Build.VERSION.RELEASE);
+
+ // 针对特定厂商的检测逻辑
+ if (manufacturer.contains("xiaomi")) {
+ Log.w(TAG, "检测到小米设备,需要在安全中心开启自启动权限");
+ return hasBasicPermission;
+ } else if (manufacturer.contains("huawei")) {
+ Log.w(TAG, "检测到华为设备,需要在手机管家开启自启动权限");
+ return hasBasicPermission;
+ } else if (manufacturer.contains("oppo")) {
+ Log.w(TAG, "检测到OPPO设备,需要在设置中开启自启动权限");
+ return hasBasicPermission;
+ } else if (manufacturer.contains("vivo")) {
+ Log.w(TAG, "检测到VIVO设备,需要在i管家开启自启动权限");
+ return hasBasicPermission;
+ } else if (manufacturer.contains("meizu")) {
+ Log.w(TAG, "检测到魅族设备,需要在手机管家开启自启动权限");
+ return hasBasicPermission;
+ } else if (manufacturer.contains("rockchip")) {
+ // Rockchip设备通常是工业设备,权限相对宽松
+ Log.i(TAG, "检测到Rockchip设备,工业设备通常自启动权限较为宽松");
+ return true; // 工业设备默认允许自启动
+ } else {
+ Log.i(TAG, "检测到其他厂商设备: " + manufacturer + ",使用基础权限检测");
+ return hasBasicPermission;
+ }
+ }
+
+ /**
+ * 设置自动启动功能状态
+ * @param enabled 是否启用
+ */
+ public void setAutoStartEnabled(boolean enabled) {
+ preferences.edit().putBoolean(KEY_AUTO_START_ENABLED, enabled).apply();
+ LogManager.logOperation(TAG, "自动启动功能" + (enabled ? "已启用" : "已禁用"));
+ }
+
+ /**
+ * 检查自动启动功能是否启用
+ * @return true 如果启用
+ */
+ public boolean isAutoStartEnabled() {
+ return preferences.getBoolean(KEY_AUTO_START_ENABLED, false);
+ }
+
+ /**
+ * 记录系统启动时间
+ */
+ public void recordBootTime() {
+ long currentTime = System.currentTimeMillis();
+ long lastBootTime = preferences.getLong(KEY_LAST_BOOT_TIME, 0);
+ int autoStartCount = preferences.getInt(KEY_AUTO_START_COUNT, 0);
+
+ preferences.edit()
+ .putLong(KEY_LAST_BOOT_TIME, currentTime)
+ .putInt(KEY_AUTO_START_COUNT, autoStartCount + 1)
+ .apply();
+
+ LogManager.logOperation(TAG, "记录系统启动时间,累计自启动次数: " + (autoStartCount + 1));
+ }
+
+ /**
+ * 获取最后一次启动时间
+ * @return 启动时间戳
+ */
+ public long getLastBootTime() {
+ return preferences.getLong(KEY_LAST_BOOT_TIME, 0);
+ }
+
+ /**
+ * 获取自动启动次数
+ * @return 启动次数
+ */
+ public int getAutoStartCount() {
+ return preferences.getInt(KEY_AUTO_START_COUNT, 0);
+ }
+
+ /**
+ * 手动触发应用启动(用于测试)
+ */
+ public void triggerAppStart() {
+ triggerAppStartWithReason("manual_trigger");
+ }
+
+ /**
+ * 触发应用启动并指定原因
+ * @param reason 启动原因
+ */
+ public void triggerAppStartWithReason(String reason) {
+ try {
+ Log.i(TAG, "触发应用启动 - 原因: " + reason);
+ LogManager.logOperation(TAG, "触发应用启动: " + reason);
+
+ // 方式1: 尝试通过Shell命令启动(推荐方式)
+ if (shellCommandManager != null && shellCommandManager.isAdbAvailable()) {
+ Log.i(TAG, "使用Shell命令启动应用");
+ boolean shellResult = shellCommandManager.startCurrentApp(reason);
+
+ if (shellResult) {
+ Log.i(TAG, "Shell命令启动成功");
+ LogManager.logOperation(TAG, "Shell命令启动应用成功");
+ return; // 启动成功,直接返回
+ } else {
+ Log.w(TAG, "Shell命令启动失败,尝试备用方式");
+ LogManager.logWarning(TAG, "Shell命令启动失败,尝试服务启动");
+ }
+ } else {
+ Log.w(TAG, "Shell命令不可用,使用服务启动方式");
+ }
+
+ // 方式2: 备用服务启动方式
+ Intent serviceIntent = new Intent(context, AutoStartService.class);
+ serviceIntent.putExtra("start_reason", reason);
+ serviceIntent.putExtra("start_time", System.currentTimeMillis());
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ context.startForegroundService(serviceIntent);
+ } else {
+ context.startService(serviceIntent);
+ }
+
+ Log.i(TAG, "备用服务启动已触发");
+ LogManager.logOperation(TAG, "备用服务启动已触发: " + reason);
+
+ } catch (Exception e) {
+ Log.e(TAG, "触发应用启动失败", e);
+ LogManager.logError(TAG, "触发应用启动失败: " + reason, e);
+
+ // 最后的备用方案:直接启动Activity
+ try {
+ Intent launchIntent = new Intent(context, com.ouxuan.oxface.MainActivity.class);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ launchIntent.putExtra("auto_start", true);
+ launchIntent.putExtra("boot_reason", reason);
+ launchIntent.putExtra("boot_time", System.currentTimeMillis());
+ context.startActivity(launchIntent);
+
+ Log.i(TAG, "最终备用方案启动成功");
+ LogManager.logOperation(TAG, "最终备用方案启动成功");
+ } catch (Exception finalException) {
+ Log.e(TAG, "所有启动方式都失败", finalException);
+ LogManager.logError(TAG, "所有启动方式都失败", finalException);
+ }
+ }
+ }
+
+ /**
+ * 获取自启动状态信息
+ * @return 状态信息字符串
+ */
+ public String getAutoStartStatusInfo() {
+ StringBuilder info = new StringBuilder();
+ info.append("自动启动功能: ").append(isAutoStartEnabled() ? "已启用" : "未启用").append("\n");
+ info.append("电池优化白名单: ").append(isIgnoringBatteryOptimizations() ? "已加入" : "未加入").append("\n");
+ info.append("累计自启动次数: ").append(getAutoStartCount()).append("\n");
+
+ long lastBootTime = getLastBootTime();
+ if (lastBootTime > 0) {
+ info.append("最后启动时间: ").append(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.getDefault()).format(new java.util.Date(lastBootTime))).append("\n");
+ } else {
+ info.append("最后启动时间: 未记录\n");
+ }
+
+ info.append("设备厂商: ").append(Build.MANUFACTURER).append("\n");
+ info.append("系统版本: ").append(Build.VERSION.RELEASE);
+
+ return info.toString();
+ }
+
+ /**
+ * 重置自启动统计信息
+ */
+ public void resetAutoStartStats() {
+ preferences.edit()
+ .remove(KEY_LAST_BOOT_TIME)
+ .remove(KEY_AUTO_START_COUNT)
+ .apply();
+
+ LogManager.logOperation(TAG, "自启动统计信息已重置");
+ }
+
+ /**
+ * 测试自启动功能(用于调试)
+ */
+ public void testAutoStartFunction() {
+ Log.i(TAG, "=== 开始测试自启动功能 ===");
+ LogManager.logOperation(TAG, "开始测试自启动功能");
+
+ // 1. 检查权限状态
+ boolean hasPermission = checkAndRequestAutoStartPermission();
+ Log.i(TAG, "权限检查结果: " + hasPermission);
+
+ // 2. 模拟系统启动
+ recordBootTime();
+
+ // 3. 测试Shell命令功能
+ if (shellCommandManager != null) {
+ Log.i(TAG, "测试Shell命令功能");
+ String shellTestResult = shellCommandManager.testAppStart();
+ Log.i(TAG, "Shell命令测试结果:\n" + shellTestResult);
+
+ // 显示Shell能力信息
+ String capabilityInfo = shellCommandManager.getShellCapabilityInfo();
+ Log.i(TAG, "Shell能力信息:\n" + capabilityInfo);
+ }
+
+ // 4. 测试广播接收器
+ try {
+ Class> bootReceiverClass = Class.forName("com.ouxuan.oxface.receiver.BootReceiver");
+ java.lang.reflect.Method testMethod = bootReceiverClass.getMethod("testBootReceiver", Context.class);
+ testMethod.invoke(null, context);
+ Log.i(TAG, "广播接收器测试完成");
+ } catch (Exception e) {
+ Log.e(TAG, "广播接收器测试失败", e);
+ }
+
+ // 5. 尝试启动服务(使用新的方法)
+ triggerAppStartWithReason("test_trigger");
+
+ // 6. 输出状态信息
+ String statusInfo = getAutoStartStatusInfo();
+ Log.i(TAG, "当前状态:\n" + statusInfo);
+
+ Log.i(TAG, "=== 自启动功能测试完成 ===");
+ LogManager.logOperation(TAG, "自启动功能测试完成");
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/utils/AutoStartTestHelper.java b/app/src/main/java/com/ouxuan/oxface/utils/AutoStartTestHelper.java
new file mode 100644
index 0000000..ee36d79
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/utils/AutoStartTestHelper.java
@@ -0,0 +1,93 @@
+package com.ouxuan.oxface.utils;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import com.ouxuan.oxface.receiver.BootReceiver;
+
+/**
+ * 自启动功能测试辅助类
+ * 提供简单的测试方法来验证自启动功能
+ */
+public class AutoStartTestHelper {
+
+ private static final String TAG = "AutoStartTestHelper";
+
+ /**
+ * 手动触发自启动测试
+ * 模拟系统启动完成事件
+ * @param context 上下文
+ */
+ public static void triggerAutoStartTest(Context context) {
+ try {
+ Log.i(TAG, "手动触发自启动测试");
+
+ // 创建模拟的启动完成Intent
+ Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED);
+ bootIntent.putExtra("test_mode", true);
+ bootIntent.putExtra("trigger_time", System.currentTimeMillis());
+
+ // 直接调用BootReceiver的onReceive方法
+ BootReceiver bootReceiver = new BootReceiver();
+ bootReceiver.onReceive(context, bootIntent);
+
+ Log.i(TAG, "自启动测试触发完成");
+
+ } catch (Exception e) {
+ Log.e(TAG, "触发自启动测试失败", e);
+ }
+ }
+
+ /**
+ * 测试AutoStartManager功能
+ * @param context 上下文
+ */
+ public static void testAutoStartManager(Context context) {
+ try {
+ Log.i(TAG, "测试AutoStartManager功能");
+
+ AutoStartManager autoStartManager = AutoStartManager.getInstance(context);
+ autoStartManager.testAutoStartFunction();
+
+ Log.i(TAG, "AutoStartManager测试完成");
+
+ } catch (Exception e) {
+ Log.e(TAG, "测试AutoStartManager失败", e);
+ }
+ }
+
+ /**
+ * 获取自启动功能状态报告
+ * @param context 上下文
+ * @return 状态报告
+ */
+ public static String getAutoStartStatusReport(Context context) {
+ try {
+ StringBuilder report = new StringBuilder();
+ report.append("=== 自启动功能状态报告 ===\n");
+
+ // 获取AutoStartManager状态
+ AutoStartManager autoStartManager = AutoStartManager.getInstance(context);
+ String statusInfo = autoStartManager.getAutoStartStatusInfo();
+ report.append(statusInfo).append("\n");
+
+ // 检查Shell命令能力
+ ShellCommandManager shellManager = ShellCommandManager.getInstance(context);
+ boolean adbAvailable = shellManager.isAdbAvailable();
+ report.append("ADB可用性: ").append(adbAvailable ? "可用" : "不可用").append("\n");
+
+ if (adbAvailable) {
+ String capabilityInfo = shellManager.getShellCapabilityInfo();
+ report.append("Shell能力信息:\n").append(capabilityInfo).append("\n");
+ }
+
+ report.append("=== 状态报告结束 ===");
+ return report.toString();
+
+ } catch (Exception e) {
+ Log.e(TAG, "获取状态报告失败", e);
+ return "获取状态报告失败: " + e.getMessage();
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/utils/BootSimulationHelper.java b/app/src/main/java/com/ouxuan/oxface/utils/BootSimulationHelper.java
new file mode 100644
index 0000000..f9b92e0
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/utils/BootSimulationHelper.java
@@ -0,0 +1,62 @@
+package com.ouxuan.oxface.utils;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import com.ouxuan.oxface.MainActivity;
+import com.ouxuan.oxface.receiver.BootReceiver;
+
+/**
+ * 系统启动模拟辅助类
+ * 用于测试自启动功能
+ */
+public class BootSimulationHelper {
+
+ private static final String TAG = "BootSimulationHelper";
+
+ /**
+ * 模拟系统启动完成事件
+ * @param context 上下文
+ */
+ public static void simulateBootCompleted(Context context) {
+ try {
+ Log.i(TAG, "开始模拟系统启动完成事件");
+
+ // 创建模拟的启动完成Intent
+ Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED);
+ bootIntent.putExtra("simulation_mode", true);
+ bootIntent.putExtra("simulation_time", System.currentTimeMillis());
+
+ // 直接调用BootReceiver的onReceive方法
+ BootReceiver bootReceiver = new BootReceiver();
+ bootReceiver.onReceive(context, bootIntent);
+
+ Log.i(TAG, "系统启动模拟完成");
+
+ } catch (Exception e) {
+ Log.e(TAG, "模拟系统启动失败", e);
+ }
+ }
+
+ /**
+ * 直接触发应用启动(不经过广播)
+ * @param context 上下文
+ */
+ public static void directStartApp(Context context) {
+ try {
+ Log.i(TAG, "直接触发应用启动");
+
+ BootReceiver bootReceiver = new BootReceiver();
+ // 使用反射调用私有方法
+ java.lang.reflect.Method method = BootReceiver.class.getDeclaredMethod("startMainActivity", Context.class);
+ method.setAccessible(true);
+ method.invoke(bootReceiver, context);
+
+ Log.i(TAG, "直接启动应用完成");
+
+ } catch (Exception e) {
+ Log.e(TAG, "直接启动应用失败", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/ouxuan/oxface/utils/ShellCommandManager.java b/app/src/main/java/com/ouxuan/oxface/utils/ShellCommandManager.java
new file mode 100644
index 0000000..f4a3fd4
--- /dev/null
+++ b/app/src/main/java/com/ouxuan/oxface/utils/ShellCommandManager.java
@@ -0,0 +1,275 @@
+package com.ouxuan.oxface.utils;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.blankj.utilcode.util.ShellUtils;
+
+/**
+ * Shell命令管理器
+ * 基于UtilCode的Shell工具实现命令执行功能
+ * 用于在权限受限环境下实现自启动等功能
+ */
+public class ShellCommandManager {
+
+ private static final String TAG = "ShellCommandManager";
+ private static volatile ShellCommandManager instance;
+ private Context context;
+
+ private ShellCommandManager(Context context) {
+ this.context = context.getApplicationContext();
+ }
+
+ /**
+ * 获取ShellCommandManager单例实例
+ * @param context 上下文
+ * @return ShellCommandManager实例
+ */
+ public static ShellCommandManager getInstance(Context context) {
+ if (instance == null) {
+ synchronized (ShellCommandManager.class) {
+ if (instance == null) {
+ instance = new ShellCommandManager(context);
+ }
+ }
+ }
+ return instance;
+ }
+
+ /**
+ * 执行Shell命令
+ * @param command 要执行的命令
+ * @param isRoot 是否需要root权限
+ * @return 命令执行结果
+ */
+ public ShellUtils.CommandResult executeCommand(String command, boolean isRoot) {
+ try {
+ Log.i(TAG, "执行Shell命令: " + command + ", 需要root: " + isRoot);
+ LogManager.logOperation(TAG, "执行Shell命令: " + command);
+
+ ShellUtils.CommandResult result;
+ if (isRoot) {
+ result = ShellUtils.execCmd(command, true);
+ } else {
+ result = ShellUtils.execCmd(command, false);
+ }
+
+ Log.i(TAG, "命令执行结果 - 返回码: " + result.result +
+ ", 成功输出: " + result.successMsg +
+ ", 错误输出: " + result.errorMsg);
+
+ LogManager.logOperation(TAG, "命令执行完成 - 返回码: " + result.result);
+
+ if (result.result == 0) {
+ LogManager.logOperation(TAG, "命令执行成功: " + result.successMsg);
+ } else {
+ LogManager.logWarning(TAG, "命令执行失败: " + result.errorMsg);
+ }
+
+ return result;
+
+ } catch (Exception e) {
+ Log.e(TAG, "执行Shell命令异常", e);
+ LogManager.logError(TAG, "执行Shell命令异常: " + command, e);
+
+ // 返回失败结果
+ ShellUtils.CommandResult errorResult = new ShellUtils.CommandResult(-1, "", "命令执行异常: " + e.getMessage());
+ return errorResult;
+ }
+ }
+
+ /**
+ * 通过ADB命令启动应用
+ * @param packageName 应用包名
+ * @param activityName Activity名称
+ * @param autoStart 是否为自启动
+ * @param bootReason 启动原因
+ * @return 是否执行成功
+ */
+ public boolean startAppByAdb(String packageName, String activityName, boolean autoStart, String bootReason) {
+ try {
+ StringBuilder command = new StringBuilder();
+ command.append("am start -n ")
+ .append(packageName)
+ .append("/")
+ .append(activityName);
+
+ if (autoStart) {
+ command.append(" --ez auto_start true");
+ }
+
+ if (bootReason != null && !bootReason.isEmpty()) {
+ command.append(" --es boot_reason \\\"").append(bootReason).append("\\\"");
+ }
+
+ // 添加时间戳
+ command.append(" --el boot_time ").append(System.currentTimeMillis());
+
+ Log.i(TAG, "准备通过ADB启动应用: " + command.toString());
+ LogManager.logOperation(TAG, "通过ADB启动应用: " + packageName);
+
+ // 执行命令(不需要root权限)
+// ShellUtils.CommandResult result = executeCommand(command.toString(), false);
+ ShellUtils.CommandResult result = executeCommand(command.toString(), true);
+
+ boolean success = result.result == 0;
+ if (success) {
+ Log.i(TAG, "通过ADB启动应用成功");
+ LogManager.logOperation(TAG, "通过ADB启动应用成功: " + packageName);
+ } else {
+ Log.w(TAG, "通过ADB启动应用失败: " + result.errorMsg);
+ LogManager.logWarning(TAG, "通过ADB启动应用失败: " + result.errorMsg);
+
+ // 如果是权限问题,记录详细信息
+ if (result.errorMsg != null && result.errorMsg.contains("Permission Denial")) {
+ Log.w(TAG, "检测到权限拒绝错误,这在某些设备上是正常的");
+ LogManager.logWarning(TAG, "权限拒绝错误,将使用备用启动方式");
+ }
+ }
+
+ return success;
+
+ } catch (Exception e) {
+ Log.e(TAG, "通过ADB启动应用异常", e);
+ LogManager.logError(TAG, "通过ADB启动应用异常", e);
+ return false;
+ }
+ }
+
+ /**
+ * 启动当前应用(自启动场景)
+ * @param bootReason 启动原因
+ * @return 是否执行成功
+ */
+ public boolean startCurrentApp(String bootReason) {
+ String packageName = context.getPackageName();
+ String activityName = "com.ouxuan.oxface.MainActivity";
+
+ Log.i(TAG, "启动当前应用 - 包名: " + packageName + ", Activity: " + activityName);
+ return startAppByAdb(packageName, activityName, true, bootReason);
+ }
+
+ /**
+ * 检查ADB是否可用
+ * @return ADB是否可用
+ */
+ public boolean isAdbAvailable() {
+ try {
+ ShellUtils.CommandResult result = executeCommand("which am", false);
+ boolean available = result.result == 0 && !result.successMsg.isEmpty();
+
+ Log.i(TAG, "ADB可用性检查: " + available);
+ LogManager.logDebug(TAG, "ADB可用性: " + available);
+
+ return available;
+
+ } catch (Exception e) {
+ Log.e(TAG, "检查ADB可用性异常", e);
+ LogManager.logError(TAG, "检查ADB可用性异常", e);
+ return false;
+ }
+ }
+
+ /**
+ * 获取当前应用包名
+ * @return 应用包名
+ */
+ public String getCurrentPackageName() {
+ return context.getPackageName();
+ }
+
+ /**
+ * 执行应用启动测试
+ * @return 测试结果信息
+ */
+ public String testAppStart() {
+ StringBuilder testResult = new StringBuilder();
+ testResult.append("=== Shell命令自启动测试 ===\n");
+
+ // 1. 检查ADB可用性
+ boolean adbAvailable = isAdbAvailable();
+ testResult.append("ADB可用性: ").append(adbAvailable ? "可用" : "不可用").append("\n");
+
+ // 2. 获取包名信息
+ String packageName = getCurrentPackageName();
+ testResult.append("当前包名: ").append(packageName).append("\n");
+
+ // 3. 尝试启动应用
+ if (adbAvailable) {
+ boolean startResult = startCurrentApp("shell_test");
+ testResult.append("启动测试: ").append(startResult ? "成功" : "失败").append("\n");
+ } else {
+ testResult.append("启动测试: 跳过(ADB不可用)\n");
+ }
+
+ testResult.append("=== 测试完成 ===");
+
+ String result = testResult.toString();
+ Log.i(TAG, result);
+ LogManager.logOperation(TAG, "Shell命令自启动测试完成");
+
+ return result;
+ }
+
+ /**
+ * 发送广播命令
+ * @param action 广播动作
+ * @param packageName 目标包名
+ * @return 是否执行成功
+ */
+ public boolean sendBroadcast(String action, String packageName) {
+ try {
+ String command = "am broadcast -a " + action;
+ if (packageName != null && !packageName.isEmpty()) {
+ command += " -p " + packageName;
+ }
+
+ Log.i(TAG, "发送广播命令: " + command);
+ ShellUtils.CommandResult result = executeCommand(command, false);
+
+ boolean success = result.result == 0;
+ if (success) {
+ Log.i(TAG, "广播发送成功");
+ LogManager.logOperation(TAG, "广播发送成功: " + action);
+ } else {
+ Log.w(TAG, "广播发送失败: " + result.errorMsg);
+ LogManager.logWarning(TAG, "广播发送失败: " + result.errorMsg);
+ }
+
+ return success;
+
+ } catch (Exception e) {
+ Log.e(TAG, "发送广播异常", e);
+ LogManager.logError(TAG, "发送广播异常", e);
+ return false;
+ }
+ }
+
+ /**
+ * 获取Shell命令执行能力信息
+ * @return 能力信息字符串
+ */
+ public String getShellCapabilityInfo() {
+ StringBuilder info = new StringBuilder();
+ info.append("Shell命令执行能力信息:\n");
+
+ // 检查基本命令
+ String[] testCommands = {"which am", "which pm", "which dumpsys", "whoami"};
+
+ for (String cmd : testCommands) {
+ ShellUtils.CommandResult result = executeCommand(cmd, false);
+ info.append("命令 '").append(cmd).append("': ");
+ if (result.result == 0) {
+ info.append("可用 - ").append(result.successMsg.trim()).append("\n");
+ } else {
+ info.append("不可用\n");
+ }
+ }
+
+ // 检查root权限
+ boolean hasRoot = ShellUtils.execCmd("id", true).result == 0;
+ info.append("Root权限: ").append(hasRoot ? "已授权" : "未授权").append("\n");
+
+ return info.toString();
+ }
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 8e2e39b..33e267c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,13 +4,7 @@
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
+
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
@@ -28,8 +22,8 @@ org.gradle.offline=false
android.sdk.path=/Users/zmt/Library/Android/sdk
# 24小时运行优化配置
-# 增大Gradle内存分配
-org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
+# Gradle内存分配和JVM参数
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError
# 并行构建优化
org.gradle.parallel=true
# 启用守护进程
@@ -40,5 +34,7 @@ org.gradle.caching=true
# Java版本兼容性配置
# 抑制不兼容警告
android.javaCompile.suppressSourceTargetDeprecationWarning=true
+# 启用AndroidX
+android.enableJetifier=true
# 启用R8优化
android.enableR8.fullMode=false
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 8ebee93..b69b7b5 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-9.0.0-bin.zip
+distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
\ No newline at end of file
diff --git a/test_auto_start.sh b/test_auto_start.sh
new file mode 100755
index 0000000..70c5c81
--- /dev/null
+++ b/test_auto_start.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# 自启动功能测试脚本
+
+echo "=== 自启动功能测试脚本 ==="
+
+# 启动应用
+echo "1. 启动应用..."
+adb shell am start -n com.ouxuan.oxface.debug/com.ouxuan.oxface.MainActivity
+
+sleep 3
+
+# 检查应用是否启动
+echo "2. 检查应用进程..."
+adb shell ps | grep oxface
+
+# 发送系统启动广播(这通常会失败,因为权限问题)
+echo "3. 尝试发送系统启动广播..."
+adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.ouxuan.oxface.debug
+
+# 查看日志
+echo "4. 查看相关日志..."
+adb logcat -d | grep -E "(BootReceiver|AutoStartManager|ShellCommandManager)" | tail -10
+
+echo "=== 测试完成 ==="
\ No newline at end of file
diff --git a/trigger_boot_test.sh b/trigger_boot_test.sh
new file mode 100755
index 0000000..5fe591f
--- /dev/null
+++ b/trigger_boot_test.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# 触发系统启动测试脚本
+
+echo "=== 触发系统启动测试 ==="
+
+# 启动应用
+echo "1. 启动应用..."
+adb shell am start -n com.ouxuan.oxface.debug/com.ouxuan.oxface.MainActivity
+
+sleep 3
+
+# 检查应用进程
+echo "2. 检查应用进程..."
+adb shell ps | grep oxface
+
+# 清除日志
+echo "3. 清除日志..."
+adb logcat -c
+
+# 手动触发BootReceiver(这通常会失败,因为权限问题)
+echo "4. 尝试触发系统启动事件..."
+adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.ouxuan.oxface.debug
+
+sleep 3
+
+# 查看日志
+echo "5. 查看相关日志..."
+adb logcat -d | grep -E "(BootReceiver|AutoStartManager|ShellCommandManager)" | tail -20
+
+echo "=== 测试完成 ==="
\ No newline at end of file