fix(supply-chain): verify CI and production inputs
Pin external actions, images, toolchains, native archives, and tvOS engine artifacts; enforce fail-closed CI checks and keep website privacy disclosures aligned with shipped behavior.
This commit is contained in:
@@ -74,15 +74,20 @@ class SystemShelfService {
|
||||
}
|
||||
|
||||
Future<dynamic> _handleMethodCall(MethodCall call) async {
|
||||
if (call.method == 'onWatchNextTap' || call.method == 'onShelfItemTap') {
|
||||
final args = call.arguments;
|
||||
final contentId = args is Map ? args['contentId'] as String? : null;
|
||||
if (contentId != null) {
|
||||
onShelfItemTap?.call(contentId);
|
||||
}
|
||||
if (call.method != 'onWatchNextTap' && call.method != 'onShelfItemTap') {
|
||||
return null;
|
||||
}
|
||||
final args = call.arguments;
|
||||
final contentId = args is Map ? args['contentId'] as String? : null;
|
||||
final callback = onShelfItemTap;
|
||||
if (contentId == null || callback == null) return false;
|
||||
callback(contentId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
Future<dynamic> handleMethodCallForTesting(MethodCall call) => _handleMethodCall(call);
|
||||
|
||||
/// Establishes the only owner allowed to publish launcher shelf state.
|
||||
///
|
||||
/// Ownership changes are synchronous. Native mutations remain serialized
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../utils/app_logger.dart';
|
||||
import '../utils/platform_detector.dart';
|
||||
|
||||
class TvosSystemNavigationService {
|
||||
@@ -8,13 +10,58 @@ class TvosSystemNavigationService {
|
||||
JSONMessageCodec(),
|
||||
);
|
||||
|
||||
static bool? _menuPassthroughEnabled;
|
||||
static bool? _latestDesiredValue;
|
||||
static bool? _lastAcknowledgedValue;
|
||||
static Future<void>? _inFlightUpdate;
|
||||
static bool _trailingUpdateRequested = false;
|
||||
|
||||
static Future<void> setMenuPassthroughEnabled(bool enabled) async {
|
||||
if (!PlatformDetector.isAppleTV()) return;
|
||||
if (_menuPassthroughEnabled == enabled) return;
|
||||
static Future<void> setMenuPassthroughEnabled(bool enabled) {
|
||||
if (!PlatformDetector.isAppleTV()) return Future<void>.value();
|
||||
|
||||
_menuPassthroughEnabled = enabled;
|
||||
await _channel.send({'menuPassthroughEnabled': enabled});
|
||||
_latestDesiredValue = enabled;
|
||||
final activeUpdate = _inFlightUpdate;
|
||||
if (activeUpdate != null) {
|
||||
_trailingUpdateRequested = true;
|
||||
return activeUpdate;
|
||||
}
|
||||
if (_lastAcknowledgedValue == enabled) return Future<void>.value();
|
||||
|
||||
final update = _runUpdateLoopAndClear();
|
||||
_inFlightUpdate = update;
|
||||
return update;
|
||||
}
|
||||
|
||||
static Future<void> _runUpdateLoopAndClear() async {
|
||||
try {
|
||||
await _runUpdateLoop();
|
||||
} finally {
|
||||
_inFlightUpdate = null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _runUpdateLoop() async {
|
||||
do {
|
||||
_trailingUpdateRequested = false;
|
||||
final desired = _latestDesiredValue;
|
||||
if (desired == null || desired == _lastAcknowledgedValue) continue;
|
||||
|
||||
try {
|
||||
final reply = await _channel.send({'menuPassthroughEnabled': desired});
|
||||
if (reply == true) {
|
||||
_lastAcknowledgedValue = desired;
|
||||
}
|
||||
} on PlatformException catch (error, stackTrace) {
|
||||
appLogger.w('Failed to update tvOS Menu passthrough state', error: error, stackTrace: stackTrace);
|
||||
}
|
||||
} while (_trailingUpdateRequested);
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static void resetForTesting() {
|
||||
assert(_inFlightUpdate == null, 'Await the active tvOS navigation update before resetting');
|
||||
_latestDesiredValue = null;
|
||||
_lastAcknowledgedValue = null;
|
||||
_trailingUpdateRequested = false;
|
||||
_inFlightUpdate = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user