fix: harden OriginOS recognition tracking
This commit is contained in:
@@ -95,6 +95,14 @@ class RecognitionStatus {
|
||||
final DateTime? accessibilityLastConnectedAt;
|
||||
final DateTime? accessibilityLastDisconnectedAt;
|
||||
final DateTime? recognitionProcessStartedAt;
|
||||
final bool keepAliveExpected;
|
||||
final bool keepAliveRunning;
|
||||
final String? keepAliveError;
|
||||
final bool recentsProtectionExpected;
|
||||
final bool recentsProtectionActive;
|
||||
final DateTime? lastRecognitionExitAt;
|
||||
final String? lastRecognitionExitReason;
|
||||
final bool taskCleanerRecoveryNeeded;
|
||||
final bool notificationAuthorized;
|
||||
final bool notificationConnected;
|
||||
final bool postNotificationsGranted;
|
||||
@@ -116,6 +124,14 @@ class RecognitionStatus {
|
||||
this.accessibilityLastConnectedAt,
|
||||
this.accessibilityLastDisconnectedAt,
|
||||
this.recognitionProcessStartedAt,
|
||||
this.keepAliveExpected = false,
|
||||
this.keepAliveRunning = false,
|
||||
this.keepAliveError,
|
||||
this.recentsProtectionExpected = false,
|
||||
this.recentsProtectionActive = false,
|
||||
this.lastRecognitionExitAt,
|
||||
this.lastRecognitionExitReason,
|
||||
this.taskCleanerRecoveryNeeded = false,
|
||||
required this.notificationAuthorized,
|
||||
required this.notificationConnected,
|
||||
required this.postNotificationsGranted,
|
||||
@@ -158,6 +174,17 @@ class RecognitionStatus {
|
||||
'accessibilityLastDisconnectedAt',
|
||||
),
|
||||
recognitionProcessStartedAt: epochDate('recognitionProcessStartedAt'),
|
||||
keepAliveExpected: value['keepAliveExpected'] as bool? ?? false,
|
||||
keepAliveRunning: value['keepAliveRunning'] as bool? ?? false,
|
||||
keepAliveError: value['keepAliveError']?.toString(),
|
||||
recentsProtectionExpected:
|
||||
value['recentsProtectionExpected'] as bool? ?? false,
|
||||
recentsProtectionActive:
|
||||
value['recentsProtectionActive'] as bool? ?? false,
|
||||
lastRecognitionExitAt: epochDate('lastRecognitionExitAt'),
|
||||
lastRecognitionExitReason: value['lastRecognitionExitReason']?.toString(),
|
||||
taskCleanerRecoveryNeeded:
|
||||
value['taskCleanerRecoveryNeeded'] as bool? ?? false,
|
||||
notificationAuthorized: value['notificationAuthorized'] as bool? ?? false,
|
||||
notificationConnected: value['notificationConnected'] as bool? ?? false,
|
||||
postNotificationsGranted:
|
||||
@@ -189,6 +216,8 @@ class RecognitionStatus {
|
||||
!accessibilityConnected &&
|
||||
accessibilityConnectionState == AccessibilityConnectionState.disconnected;
|
||||
|
||||
bool get keepAliveNeedsRecovery => keepAliveExpected && !keepAliveRunning;
|
||||
|
||||
String get accessibilityConnectionLabel =>
|
||||
switch (accessibilityConnectionState) {
|
||||
AccessibilityConnectionState.unauthorized => '未授权',
|
||||
@@ -320,6 +349,7 @@ class SpeechEvent {
|
||||
/// Android native capabilities for screenshots, AI progress and speech.
|
||||
class ScreenshotChannel {
|
||||
static const _channel = MethodChannel('com.miaoji/screenshot');
|
||||
static Future<RecognitionStatus>? _activeAccessibilityConnectionWait;
|
||||
static void Function(String path)? _screenshotReady;
|
||||
static void Function(String error)? _screenshotError;
|
||||
static void Function(SpeechEvent event)? _speechEvent;
|
||||
@@ -472,13 +502,32 @@ class ScreenshotChannel {
|
||||
static Future<RecognitionStatus> waitForAccessibilityConnection({
|
||||
Duration timeout = const Duration(seconds: 5),
|
||||
Duration interval = const Duration(milliseconds: 500),
|
||||
}) {
|
||||
final active = _activeAccessibilityConnectionWait;
|
||||
if (active != null) return active;
|
||||
final operation = _waitForAccessibilityConnection(
|
||||
timeout: timeout,
|
||||
interval: interval,
|
||||
);
|
||||
_activeAccessibilityConnectionWait = operation;
|
||||
return operation.whenComplete(() {
|
||||
if (identical(_activeAccessibilityConnectionWait, operation)) {
|
||||
_activeAccessibilityConnectionWait = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static Future<RecognitionStatus> _waitForAccessibilityConnection({
|
||||
required Duration timeout,
|
||||
required Duration interval,
|
||||
}) async {
|
||||
var status = await recognitionStatus();
|
||||
final recognitionEnabled =
|
||||
status.accessibilityEvents || status.aiScreenshot;
|
||||
if (!recognitionEnabled ||
|
||||
!status.accessibilityAuthorized ||
|
||||
status.accessibilityConnected) {
|
||||
status.accessibilityConnected ||
|
||||
status.taskCleanerRecoveryNeeded) {
|
||||
return status;
|
||||
}
|
||||
final deadline = DateTime.now().add(timeout);
|
||||
@@ -487,6 +536,7 @@ class ScreenshotChannel {
|
||||
status = await recognitionStatus();
|
||||
if (!status.accessibilityAuthorized ||
|
||||
status.accessibilityConnected ||
|
||||
status.taskCleanerRecoveryNeeded ||
|
||||
!(status.accessibilityEvents || status.aiScreenshot)) {
|
||||
return status;
|
||||
}
|
||||
@@ -494,6 +544,15 @@ class ScreenshotChannel {
|
||||
return status;
|
||||
}
|
||||
|
||||
static Future<bool> ensureRecognitionKeepAlive() async {
|
||||
try {
|
||||
return await _channel.invokeMethod<bool>('ensureRecognitionKeepAlive') ??
|
||||
false;
|
||||
} on MissingPluginException {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> clearRecognitionDiagnostic() async {
|
||||
try {
|
||||
return await _channel.invokeMethod<bool>('clearRecognitionDiagnostic') ??
|
||||
|
||||
Reference in New Issue
Block a user