Initial support for more finely-grained a11y features on Window (flutter/engine#5901)
This commit is contained in:
@@ -70,9 +70,12 @@ void _updateSemanticsEnabled(bool enabled) {
|
||||
_invoke(window.onSemanticsEnabledChanged, window._onSemanticsEnabledChangedZone);
|
||||
}
|
||||
|
||||
void _updateAssistiveTechnologyEnabled(bool enabled) {
|
||||
window._assistiveTechnologyEnabled = enabled;
|
||||
_invoke(window.onAssistiveTechnologyEnabled, window._onAssistiveTechnologyEnabledZone);
|
||||
void _updateAccessibilityFeatures(int values) {
|
||||
final AccessibilityFeatures newFeatures = new AccessibilityFeatures._(values);
|
||||
if (newFeatures == window._accessibilityFeatures)
|
||||
return;
|
||||
window._accessibilityFeatures = newFeatures;
|
||||
_invoke(window.onAccessibilityFeaturesChanged, window._onAccessibilityFlagsChangedZone);
|
||||
}
|
||||
|
||||
void _dispatchPlatformMessage(String name, ByteData data, int responseId) {
|
||||
|
||||
@@ -649,31 +649,6 @@ class Window {
|
||||
_onSemanticsEnabledChangedZone = Zone.current;
|
||||
}
|
||||
|
||||
/// Whether the user is using assitive technologies to interact with the
|
||||
/// application.
|
||||
///
|
||||
/// This includes screen readers such as TalkBack on Android and VoiceOVer
|
||||
/// on iOS, as well as hardware switches, and more.
|
||||
///
|
||||
/// The [onAssistiveTechnologyEnabled] callback is called whenever this value
|
||||
/// changes.
|
||||
bool get assistiveTechnologyEnabled => _assistiveTechnologyEnabled;
|
||||
bool _assistiveTechnologyEnabled = false;
|
||||
|
||||
/// A callback that is invoked when the value of [assistiveTechnologyEnabled]
|
||||
/// changes.
|
||||
///
|
||||
/// The framework invokes this callback in the same zone in which the callback
|
||||
/// was set.
|
||||
VoidCallback get onAssistiveTechnologyEnabled => _onAssistiveTechnologyEnabled;
|
||||
VoidCallback _onAssistiveTechnologyEnabled;
|
||||
Zone _onAssistiveTechnologyEnabledZone;
|
||||
set onAssistiveTechnologyEnabled(VoidCallback callback) {
|
||||
_onAssistiveTechnologyEnabled = callback;
|
||||
_onAssistiveTechnologyEnabledZone = Zone.current;
|
||||
}
|
||||
|
||||
|
||||
/// A callback that is invoked whenever the user requests an action to be
|
||||
/// performed.
|
||||
///
|
||||
@@ -690,6 +665,22 @@ class Window {
|
||||
_onSemanticsActionZone = Zone.current;
|
||||
}
|
||||
|
||||
/// Additional accessibility features that may be enabled by the platform.
|
||||
AccessibilityFeatures get accessibilityFeatures => _accessibilityFeatures;
|
||||
AccessibilityFeatures _accessibilityFeatures;
|
||||
|
||||
/// A callback that is invoked when the value of [accessibilityFlags] changes.
|
||||
///
|
||||
/// The framework invokes this callback in the same zone in which the
|
||||
/// callback was set.
|
||||
VoidCallback get onAccessibilityFeaturesChanged => _onAccessibilityFeaturesChanged;
|
||||
VoidCallback _onAccessibilityFeaturesChanged;
|
||||
Zone _onAccessibilityFlagsChangedZone;
|
||||
set onAccessibilityFeaturesChanged(VoidCallback callback) {
|
||||
_onAccessibilityFeaturesChanged = callback;
|
||||
_onAccessibilityFlagsChangedZone = Zone.current;
|
||||
}
|
||||
|
||||
/// Change the retained semantics data about this window.
|
||||
///
|
||||
/// If [semanticsEnabled] is true, the user has requested that this funciton
|
||||
@@ -760,6 +751,57 @@ class Window {
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional accessibility features that may be enabled by the platform.
|
||||
///
|
||||
/// It is not possible to enable these settings from Flutter, instead they are
|
||||
/// used by the platform to indicate that additional accessibility features are
|
||||
/// enabled.
|
||||
class AccessibilityFeatures {
|
||||
const AccessibilityFeatures._(this._index);
|
||||
|
||||
static const int _kAccessibleNavigation = 1 << 0;
|
||||
static const int _kInvertColorsIndex = 1 << 1;
|
||||
static const int _kDisableAnimationsIndex = 1 << 2;
|
||||
|
||||
// A bitfield which represents each enabled feature.
|
||||
final int _index;
|
||||
|
||||
/// Whether there is a running accessibility service which is changing the
|
||||
/// interaction model of the device.
|
||||
///
|
||||
/// For example, TalkBack on Android and VoiceOver on iOS enable this flag.
|
||||
bool get accessibleNavigation => _kAccessibleNavigation & _index != 0;
|
||||
|
||||
/// The platform is inverting the colors of the application.
|
||||
bool get invertColors => _kInvertColorsIndex & _index != 0;
|
||||
|
||||
/// The platform is requesting that animations be disabled or simplified.
|
||||
bool get disableAnimations => _kDisableAnimationsIndex & _index != 0;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final List<String> features = <String>[];
|
||||
if (accessibleNavigation)
|
||||
features.add('accessibleNavigation');
|
||||
if (invertColors)
|
||||
features.add('invertColors');
|
||||
if (disableAnimations)
|
||||
features.add('disableAnimations');
|
||||
return 'AccessibilityFeatures$features';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
final AccessibilityFeatures typedOther = other;
|
||||
return _index == typedOther._index;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => _index.hashCode;
|
||||
}
|
||||
|
||||
/// The [Window] singleton. This object exposes the size of the display, the
|
||||
/// core scheduler API, the input event callback, the graphics drawing API, and
|
||||
/// other such core services.
|
||||
|
||||
@@ -198,14 +198,14 @@ void Window::UpdateSemanticsEnabled(bool enabled) {
|
||||
{ToDart(enabled)});
|
||||
}
|
||||
|
||||
void Window::UpdateAssistiveTechnologyEnabled(bool enabled) {
|
||||
void Window::UpdateAccessibilityFeatures(int32_t values) {
|
||||
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
|
||||
if (!dart_state)
|
||||
return;
|
||||
tonic::DartState::Scope scope(dart_state);
|
||||
|
||||
DartInvokeField(library_.value(), "_updateAssistiveTechnologyEnabled",
|
||||
{ToDart(enabled)});
|
||||
DartInvokeField(library_.value(), "_updateAccessibilityFeatures",
|
||||
{ToDart(values)});
|
||||
}
|
||||
|
||||
void Window::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
|
||||
|
||||
@@ -25,6 +25,13 @@ class Scene;
|
||||
|
||||
Dart_Handle ToByteData(const std::vector<uint8_t>& buffer);
|
||||
|
||||
// Must match the AccessibilityFeatureFlag enum in window.dart.
|
||||
enum class AccessibilityFeatureFlag : int32_t {
|
||||
kAccessibleNavigation = 1 << 0,
|
||||
kInvertColors = 1 << 1,
|
||||
kDisableAnimations = 1 << 2,
|
||||
};
|
||||
|
||||
class WindowClient {
|
||||
public:
|
||||
virtual std::string DefaultRouteName() = 0;
|
||||
@@ -54,7 +61,7 @@ class Window final {
|
||||
const std::string& country_code);
|
||||
void UpdateUserSettingsData(const std::string& data);
|
||||
void UpdateSemanticsEnabled(bool enabled);
|
||||
void UpdateAssistiveTechnologyEnabled(bool enabled);
|
||||
void UpdateAccessibilityFeatures(int32_t flags);
|
||||
void DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
|
||||
void DispatchPointerDataPacket(const PointerDataPacket& packet);
|
||||
void DispatchSemanticsAction(int32_t id,
|
||||
|
||||
@@ -19,7 +19,7 @@ dart:ui,::,_getScheduleMicrotaskClosure
|
||||
dart:ui,::,_setupHooks
|
||||
dart:ui,::,_updateLocale
|
||||
dart:ui,::,_updateSemanticsEnabled
|
||||
dart:ui,::,_updateAssistiveTechnologyEnabled
|
||||
dart:ui,::,_updateAccessibilityFeatures
|
||||
dart:ui,::,_updateUserSettingsData
|
||||
dart:ui,::,_updateWindowMetrics
|
||||
dart:ui,_ImageInfo,get:width
|
||||
|
||||
@@ -126,8 +126,7 @@ bool RuntimeController::FlushRuntimeStateToIsolate() {
|
||||
return SetViewportMetrics(window_data_.viewport_metrics) &&
|
||||
SetLocale(window_data_.language_code, window_data_.country_code) &&
|
||||
SetSemanticsEnabled(window_data_.semantics_enabled) &&
|
||||
SetAssistiveTechnologyEnabled(
|
||||
window_data_.assistive_technology_enabled);
|
||||
SetAccessibilityFeatures(window_data_.accessibility_feature_flags_);
|
||||
}
|
||||
|
||||
bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) {
|
||||
@@ -175,11 +174,11 @@ bool RuntimeController::SetSemanticsEnabled(bool enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuntimeController::SetAssistiveTechnologyEnabled(bool enabled) {
|
||||
window_data_.assistive_technology_enabled = enabled;
|
||||
bool RuntimeController::SetAccessibilityFeatures(int32_t flags) {
|
||||
window_data_.accessibility_feature_flags_ = flags;
|
||||
if (auto window = GetWindowIfAvailable()) {
|
||||
window->UpdateAssistiveTechnologyEnabled(
|
||||
window_data_.assistive_technology_enabled);
|
||||
window->UpdateAccessibilityFeatures(
|
||||
window_data_.accessibility_feature_flags_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class RuntimeController final : public WindowClient {
|
||||
|
||||
bool SetSemanticsEnabled(bool enabled);
|
||||
|
||||
bool SetAssistiveTechnologyEnabled(bool enabled);
|
||||
bool SetAccessibilityFeatures(int32_t flags);
|
||||
|
||||
bool BeginFrame(fml::TimePoint frame_time);
|
||||
|
||||
@@ -83,6 +83,7 @@ class RuntimeController final : public WindowClient {
|
||||
std::string user_settings_data = "{}";
|
||||
bool semantics_enabled = false;
|
||||
bool assistive_technology_enabled = false;
|
||||
int32_t accessibility_feature_flags_ = 0;
|
||||
};
|
||||
|
||||
RuntimeDelegate& client_;
|
||||
|
||||
@@ -345,8 +345,8 @@ void Engine::SetSemanticsEnabled(bool enabled) {
|
||||
runtime_controller_->SetSemanticsEnabled(enabled);
|
||||
}
|
||||
|
||||
void Engine::SetAssistiveTechnologyEnabled(bool enabled) {
|
||||
runtime_controller_->SetAssistiveTechnologyEnabled(enabled);
|
||||
void Engine::SetAccessibilityFeatures(int32_t flags) {
|
||||
runtime_controller_->SetAccessibilityFeatures(flags);
|
||||
}
|
||||
|
||||
void Engine::StopAnimator() {
|
||||
|
||||
@@ -99,7 +99,7 @@ class Engine final : public blink::RuntimeDelegate {
|
||||
|
||||
void SetSemanticsEnabled(bool enabled);
|
||||
|
||||
void SetAssistiveTechnologyEnabled(bool enabled);
|
||||
void SetAccessibilityFeatures(int32_t flags);
|
||||
|
||||
void ScheduleFrame(bool regenerate_layer_tree = true) override;
|
||||
|
||||
|
||||
@@ -52,8 +52,8 @@ void PlatformView::SetSemanticsEnabled(bool enabled) {
|
||||
delegate_.OnPlatformViewSetSemanticsEnabled(*this, enabled);
|
||||
}
|
||||
|
||||
void PlatformView::SetAssistiveTechnologyEnabled(bool enabled) {
|
||||
delegate_.OnPlatformViewSetAssistiveTechnologyEnabled(*this, enabled);
|
||||
void PlatformView::SetAccessibilityFeatures(int32_t flags) {
|
||||
delegate_.OnPlatformViewSetAccessibilityFeatures(*this, flags);
|
||||
}
|
||||
|
||||
void PlatformView::SetViewportMetrics(const blink::ViewportMetrics& metrics) {
|
||||
|
||||
@@ -58,9 +58,9 @@ class PlatformView {
|
||||
virtual void OnPlatformViewSetSemanticsEnabled(const PlatformView& view,
|
||||
bool enabled) = 0;
|
||||
|
||||
virtual void OnPlatformViewSetAssistiveTechnologyEnabled(
|
||||
virtual void OnPlatformViewSetAccessibilityFeatures(
|
||||
const PlatformView& view,
|
||||
bool enabled) = 0;
|
||||
int32_t flags) = 0;
|
||||
|
||||
virtual void OnPlatformViewRegisterTexture(
|
||||
const PlatformView& view,
|
||||
@@ -88,7 +88,7 @@ class PlatformView {
|
||||
|
||||
virtual void SetSemanticsEnabled(bool enabled);
|
||||
|
||||
virtual void SetAssistiveTechnologyEnabled(bool enabled);
|
||||
virtual void SetAccessibilityFeatures(int32_t flags);
|
||||
|
||||
void SetViewportMetrics(const blink::ViewportMetrics& metrics);
|
||||
|
||||
|
||||
@@ -562,17 +562,17 @@ void Shell::OnPlatformViewSetSemanticsEnabled(const PlatformView& view,
|
||||
});
|
||||
}
|
||||
|
||||
void Shell::OnPlatformViewSetAssistiveTechnologyEnabled(
|
||||
const PlatformView& view,
|
||||
bool enabled) {
|
||||
// |shell::PlatformView::Delegate|
|
||||
void Shell::OnPlatformViewSetAccessibilityFeatures(const PlatformView& view,
|
||||
int32_t flags) {
|
||||
FML_DCHECK(is_setup_);
|
||||
FML_DCHECK(&view == platform_view_.get());
|
||||
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
|
||||
|
||||
task_runners_.GetUITaskRunner()->PostTask(
|
||||
[engine = engine_->GetWeakPtr(), enabled] {
|
||||
[engine = engine_->GetWeakPtr(), flags] {
|
||||
if (engine) {
|
||||
engine->SetAssistiveTechnologyEnabled(enabled);
|
||||
engine->SetAccessibilityFeatures(flags);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -147,9 +147,9 @@ class Shell final : public PlatformView::Delegate,
|
||||
void OnPlatformViewSetSemanticsEnabled(const PlatformView& view,
|
||||
bool enabled) override;
|
||||
|
||||
// |shell::PlatformView::Delegate|
|
||||
void OnPlatformViewSetAssistiveTechnologyEnabled(const PlatformView& view,
|
||||
bool enabled) override;
|
||||
// |shell:PlatformView::Delegate|
|
||||
void OnPlatformViewSetAccessibilityFeatures(const PlatformView& view,
|
||||
int32_t flags) override;
|
||||
|
||||
// |shell::PlatformView::Delegate|
|
||||
void OnPlatformViewRegisterTexture(
|
||||
|
||||
@@ -11,6 +11,10 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.ContentObserver;
|
||||
import android.provider.Settings;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.SurfaceTexture;
|
||||
@@ -41,23 +45,24 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
/**
|
||||
* An Android view containing a Flutter app.
|
||||
*/
|
||||
public class FlutterView
|
||||
extends SurfaceView implements BinaryMessenger, TextureRegistry,
|
||||
AccessibilityManager.AccessibilityStateChangeListener {
|
||||
public class FlutterView extends SurfaceView
|
||||
implements BinaryMessenger, TextureRegistry, AccessibilityManager.AccessibilityStateChangeListener {
|
||||
/**
|
||||
* Interface for those objects that maintain and expose a reference to a
|
||||
* {@code FlutterView} (such as a full-screen Flutter activity).
|
||||
*
|
||||
* <p>This indirection is provided to support applications that use an
|
||||
* activity other than {@link io.flutter.app.FlutterActivity} (e.g. Android
|
||||
* v4 support library's {@code FragmentActivity}). It allows Flutter plugins
|
||||
* to deal in this interface and not require that the activity be a subclass
|
||||
* of {@code FlutterActivity}.</p>
|
||||
* <p>
|
||||
* This indirection is provided to support applications that use an activity
|
||||
* other than {@link io.flutter.app.FlutterActivity} (e.g. Android v4 support
|
||||
* library's {@code FragmentActivity}). It allows Flutter plugins to deal in
|
||||
* this interface and not require that the activity be a subclass of
|
||||
* {@code FlutterActivity}.
|
||||
* </p>
|
||||
*/
|
||||
public interface Provider {
|
||||
/**
|
||||
* Returns a reference to the Flutter view maintained by this object.
|
||||
* This may be {@code null}.
|
||||
* Returns a reference to the Flutter view maintained by this object. This may
|
||||
* be {@code null}.
|
||||
*/
|
||||
FlutterView getFlutterView();
|
||||
}
|
||||
@@ -96,6 +101,7 @@ public class FlutterView
|
||||
private final List<FirstFrameListener> mFirstFrameListeners;
|
||||
private final AtomicLong nextTextureId = new AtomicLong(0L);
|
||||
private FlutterNativeView mNativeView;
|
||||
private final AnimationScaleObserver mAnimationScaleObserver;
|
||||
private boolean mIsSoftwareRenderingEnabled = false; // using the software renderer or not
|
||||
private InputConnection mLastInputConnection;
|
||||
|
||||
@@ -111,7 +117,7 @@ public class FlutterView
|
||||
super(context, attrs);
|
||||
|
||||
mIsSoftwareRenderingEnabled = nativeGetIsSoftwareRenderingEnabled();
|
||||
|
||||
mAnimationScaleObserver = new AnimationScaleObserver(new Handler());
|
||||
mMetrics = new ViewportMetrics();
|
||||
mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
|
||||
setFocusable(true);
|
||||
@@ -128,8 +134,7 @@ public class FlutterView
|
||||
int color = 0xFF000000;
|
||||
TypedValue typedValue = new TypedValue();
|
||||
context.getTheme().resolveAttribute(android.R.attr.colorBackground, typedValue, true);
|
||||
if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT
|
||||
&& typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) {
|
||||
if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT && typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) {
|
||||
color = typedValue.data;
|
||||
}
|
||||
// TODO(abarth): Consider letting the developer override this color.
|
||||
@@ -156,29 +161,21 @@ public class FlutterView
|
||||
};
|
||||
getHolder().addCallback(mSurfaceCallback);
|
||||
|
||||
mAccessibilityManager =
|
||||
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
|
||||
mAccessibilityManager = (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
|
||||
|
||||
mActivityLifecycleListeners = new ArrayList<>();
|
||||
mFirstFrameListeners = new ArrayList<>();
|
||||
|
||||
// Configure the platform plugins and flutter channels.
|
||||
mFlutterLocalizationChannel =
|
||||
new MethodChannel(this, "flutter/localization", JSONMethodCodec.INSTANCE);
|
||||
mFlutterNavigationChannel =
|
||||
new MethodChannel(this, "flutter/navigation", JSONMethodCodec.INSTANCE);
|
||||
mFlutterKeyEventChannel =
|
||||
new BasicMessageChannel<>(this, "flutter/keyevent", JSONMessageCodec.INSTANCE);
|
||||
mFlutterLifecycleChannel =
|
||||
new BasicMessageChannel<>(this, "flutter/lifecycle", StringCodec.INSTANCE);
|
||||
mFlutterSystemChannel =
|
||||
new BasicMessageChannel<>(this, "flutter/system", JSONMessageCodec.INSTANCE);
|
||||
mFlutterSettingsChannel =
|
||||
new BasicMessageChannel<>(this, "flutter/settings", JSONMessageCodec.INSTANCE);
|
||||
mFlutterLocalizationChannel = new MethodChannel(this, "flutter/localization", JSONMethodCodec.INSTANCE);
|
||||
mFlutterNavigationChannel = new MethodChannel(this, "flutter/navigation", JSONMethodCodec.INSTANCE);
|
||||
mFlutterKeyEventChannel = new BasicMessageChannel<>(this, "flutter/keyevent", JSONMessageCodec.INSTANCE);
|
||||
mFlutterLifecycleChannel = new BasicMessageChannel<>(this, "flutter/lifecycle", StringCodec.INSTANCE);
|
||||
mFlutterSystemChannel = new BasicMessageChannel<>(this, "flutter/system", JSONMessageCodec.INSTANCE);
|
||||
mFlutterSettingsChannel = new BasicMessageChannel<>(this, "flutter/settings", JSONMessageCodec.INSTANCE);
|
||||
|
||||
PlatformPlugin platformPlugin = new PlatformPlugin(activity);
|
||||
MethodChannel flutterPlatformChannel =
|
||||
new MethodChannel(this, "flutter/platform", JSONMethodCodec.INSTANCE);
|
||||
MethodChannel flutterPlatformChannel = new MethodChannel(this, "flutter/platform", JSONMethodCodec.INSTANCE);
|
||||
flutterPlatformChannel.setMethodCallHandler(platformPlugin);
|
||||
addActivityLifecycleListener(platformPlugin);
|
||||
mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
@@ -266,6 +263,7 @@ public class FlutterView
|
||||
}
|
||||
|
||||
public void onPostResume() {
|
||||
updateAccessibilityFeatures();
|
||||
for (ActivityLifecycleListener listener : mActivityLifecycleListeners) {
|
||||
listener.onPostResume();
|
||||
}
|
||||
@@ -283,8 +281,8 @@ public class FlutterView
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a listener that will be called once when the FlutterView renders its first frame
|
||||
* to the underlaying SurfaceView.
|
||||
* Provide a listener that will be called once when the FlutterView renders its
|
||||
* first frame to the underlaying SurfaceView.
|
||||
*/
|
||||
public void addFirstFrameListener(FirstFrameListener listener) {
|
||||
mFirstFrameListeners.add(listener);
|
||||
@@ -317,8 +315,7 @@ public class FlutterView
|
||||
}
|
||||
|
||||
private void setLocale(Locale locale) {
|
||||
mFlutterLocalizationChannel.invokeMethod(
|
||||
"setLocale", Arrays.asList(locale.getLanguage(), locale.getCountry()));
|
||||
mFlutterLocalizationChannel.invokeMethod("setLocale", Arrays.asList(locale.getLanguage(), locale.getCountry()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -333,7 +330,8 @@ public class FlutterView
|
||||
}
|
||||
|
||||
public FlutterNativeView detach() {
|
||||
if (!isAttached()) return null;
|
||||
if (!isAttached())
|
||||
return null;
|
||||
if (mDiscoveryReceiver != null) {
|
||||
getContext().unregisterReceiver(mDiscoveryReceiver);
|
||||
}
|
||||
@@ -346,7 +344,8 @@ public class FlutterView
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (!isAttached()) return;
|
||||
if (!isAttached())
|
||||
return;
|
||||
|
||||
if (mDiscoveryReceiver != null) {
|
||||
getContext().unregisterReceiver(mDiscoveryReceiver);
|
||||
@@ -411,15 +410,15 @@ public class FlutterView
|
||||
|
||||
private int getPointerDeviceTypeForToolType(int toolType) {
|
||||
switch (toolType) {
|
||||
case MotionEvent.TOOL_TYPE_FINGER:
|
||||
return kPointerDeviceKindTouch;
|
||||
case MotionEvent.TOOL_TYPE_STYLUS:
|
||||
return kPointerDeviceKindStylus;
|
||||
case MotionEvent.TOOL_TYPE_MOUSE:
|
||||
return kPointerDeviceKindMouse;
|
||||
default:
|
||||
// MotionEvent.TOOL_TYPE_UNKNOWN will reach here.
|
||||
return -1;
|
||||
case MotionEvent.TOOL_TYPE_FINGER:
|
||||
return kPointerDeviceKindTouch;
|
||||
case MotionEvent.TOOL_TYPE_STYLUS:
|
||||
return kPointerDeviceKindStylus;
|
||||
case MotionEvent.TOOL_TYPE_MOUSE:
|
||||
return kPointerDeviceKindMouse;
|
||||
default:
|
||||
// MotionEvent.TOOL_TYPE_UNKNOWN will reach here.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,8 +459,7 @@ public class FlutterView
|
||||
packet.putDouble(1.0); // pressure_max
|
||||
|
||||
if (pointerKind == kPointerDeviceKindStylus) {
|
||||
packet.putDouble(
|
||||
event.getAxisValue(MotionEvent.AXIS_DISTANCE, pointerIndex)); // distance
|
||||
packet.putDouble(event.getAxisValue(MotionEvent.AXIS_DISTANCE, pointerIndex)); // distance
|
||||
packet.putDouble(0.0); // distance_max
|
||||
} else {
|
||||
packet.putDouble(0.0); // distance
|
||||
@@ -474,8 +472,7 @@ public class FlutterView
|
||||
packet.putDouble(0.0); // radius_min
|
||||
packet.putDouble(0.0); // radius_max
|
||||
|
||||
packet.putDouble(
|
||||
event.getAxisValue(MotionEvent.AXIS_ORIENTATION, pointerIndex)); // orientation
|
||||
packet.putDouble(event.getAxisValue(MotionEvent.AXIS_ORIENTATION, pointerIndex)); // orientation
|
||||
|
||||
if (pointerKind == kPointerDeviceKindStylus) {
|
||||
packet.putDouble(event.getAxisValue(MotionEvent.AXIS_TILT, pointerIndex)); // tilt
|
||||
@@ -505,16 +502,14 @@ public class FlutterView
|
||||
|
||||
int pointerCount = event.getPointerCount();
|
||||
|
||||
ByteBuffer packet =
|
||||
ByteBuffer.allocateDirect(pointerCount * kPointerDataFieldCount * kBytePerField);
|
||||
ByteBuffer packet = ByteBuffer.allocateDirect(pointerCount * kPointerDataFieldCount * kBytePerField);
|
||||
packet.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
int maskedAction = event.getActionMasked();
|
||||
// ACTION_UP, ACTION_POINTER_UP, ACTION_DOWN, and ACTION_POINTER_DOWN
|
||||
// only apply to a single pointer, other events apply to all pointers.
|
||||
if (maskedAction == MotionEvent.ACTION_UP || maskedAction == MotionEvent.ACTION_POINTER_UP
|
||||
|| maskedAction == MotionEvent.ACTION_DOWN
|
||||
|| maskedAction == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
|| maskedAction == MotionEvent.ACTION_DOWN || maskedAction == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
addPointerForIndex(event, event.getActionIndex(), packet);
|
||||
} else {
|
||||
// ACTION_MOVE may not actually mean all pointers have moved
|
||||
@@ -596,14 +591,16 @@ public class FlutterView
|
||||
}
|
||||
|
||||
void assertAttached() {
|
||||
if (!isAttached()) throw new AssertionError("Platform view is not attached");
|
||||
if (!isAttached())
|
||||
throw new AssertionError("Platform view is not attached");
|
||||
}
|
||||
|
||||
private void preRun() {
|
||||
resetAccessibilityTree();
|
||||
}
|
||||
|
||||
private void postRun() {}
|
||||
private void postRun() {
|
||||
}
|
||||
|
||||
public void runFromBundle(String bundlePath, String snapshotOverride) {
|
||||
runFromBundle(bundlePath, snapshotOverride, "main", false);
|
||||
@@ -631,53 +628,46 @@ public class FlutterView
|
||||
return nativeGetBitmap(mNativeView.get());
|
||||
}
|
||||
|
||||
private static native void nativeSurfaceCreated(
|
||||
long nativePlatformViewAndroid, Surface surface, int backgroundColor);
|
||||
private static native void nativeSurfaceCreated(long nativePlatformViewAndroid, Surface surface,
|
||||
int backgroundColor);
|
||||
|
||||
private static native void nativeSurfaceChanged(
|
||||
long nativePlatformViewAndroid, int width, int height);
|
||||
private static native void nativeSurfaceChanged(long nativePlatformViewAndroid, int width, int height);
|
||||
|
||||
private static native void nativeSurfaceDestroyed(long nativePlatformViewAndroid);
|
||||
|
||||
private static native void nativeSetViewportMetrics(long nativePlatformViewAndroid,
|
||||
float devicePixelRatio, int physicalWidth, int physicalHeight, int physicalPaddingTop,
|
||||
int physicalPaddingRight, int physicalPaddingBottom, int physicalPaddingLeft,
|
||||
int physicalViewInsetTop, int physicalViewInsetRight, int physicalViewInsetBottom,
|
||||
int physicalViewInsetLeft);
|
||||
private static native void nativeSetViewportMetrics(long nativePlatformViewAndroid, float devicePixelRatio,
|
||||
int physicalWidth, int physicalHeight, int physicalPaddingTop, int physicalPaddingRight,
|
||||
int physicalPaddingBottom, int physicalPaddingLeft, int physicalViewInsetTop, int physicalViewInsetRight,
|
||||
int physicalViewInsetBottom, int physicalViewInsetLeft);
|
||||
|
||||
private static native Bitmap nativeGetBitmap(long nativePlatformViewAndroid);
|
||||
|
||||
private static native void nativeDispatchPointerDataPacket(
|
||||
long nativePlatformViewAndroid, ByteBuffer buffer, int position);
|
||||
private static native void nativeDispatchPointerDataPacket(long nativePlatformViewAndroid, ByteBuffer buffer,
|
||||
int position);
|
||||
|
||||
private static native void nativeDispatchSemanticsAction(
|
||||
long nativePlatformViewAndroid, int id, int action, ByteBuffer args, int argsPosition);
|
||||
private static native void nativeDispatchSemanticsAction(long nativePlatformViewAndroid, int id, int action,
|
||||
ByteBuffer args, int argsPosition);
|
||||
|
||||
private static native void nativeSetSemanticsEnabled(
|
||||
long nativePlatformViewAndroid, boolean enabled);
|
||||
private static native void nativeSetSemanticsEnabled(long nativePlatformViewAndroid, boolean enabled);
|
||||
|
||||
private static native void nativeSetAssistiveTechnologyEnabled(
|
||||
long nativePlatformViewAndroid, boolean enabled);
|
||||
private static native void nativeSetAccessibilityFeatures(long nativePlatformViewAndroid, int flags);
|
||||
|
||||
private static native boolean nativeGetIsSoftwareRenderingEnabled();
|
||||
|
||||
private static native void nativeRegisterTexture(
|
||||
long nativePlatformViewAndroid, long textureId, SurfaceTexture surfaceTexture);
|
||||
private static native void nativeRegisterTexture(long nativePlatformViewAndroid, long textureId,
|
||||
SurfaceTexture surfaceTexture);
|
||||
|
||||
private static native void nativeMarkTextureFrameAvailable(
|
||||
long nativePlatformViewAndroid, long textureId);
|
||||
private static native void nativeMarkTextureFrameAvailable(long nativePlatformViewAndroid, long textureId);
|
||||
|
||||
private static native void nativeUnregisterTexture(
|
||||
long nativePlatformViewAndroid, long textureId);
|
||||
private static native void nativeUnregisterTexture(long nativePlatformViewAndroid, long textureId);
|
||||
|
||||
private void updateViewportMetrics() {
|
||||
if (!isAttached()) return;
|
||||
nativeSetViewportMetrics(mNativeView.get(), mMetrics.devicePixelRatio,
|
||||
mMetrics.physicalWidth, mMetrics.physicalHeight, mMetrics.physicalPaddingTop,
|
||||
mMetrics.physicalPaddingRight, mMetrics.physicalPaddingBottom,
|
||||
mMetrics.physicalPaddingLeft, mMetrics.physicalViewInsetTop,
|
||||
mMetrics.physicalViewInsetRight, mMetrics.physicalViewInsetBottom,
|
||||
mMetrics.physicalViewInsetLeft);
|
||||
if (!isAttached())
|
||||
return;
|
||||
nativeSetViewportMetrics(mNativeView.get(), mMetrics.devicePixelRatio, mMetrics.physicalWidth,
|
||||
mMetrics.physicalHeight, mMetrics.physicalPaddingTop, mMetrics.physicalPaddingRight,
|
||||
mMetrics.physicalPaddingBottom, mMetrics.physicalPaddingLeft, mMetrics.physicalViewInsetTop,
|
||||
mMetrics.physicalViewInsetRight, mMetrics.physicalViewInsetBottom, mMetrics.physicalViewInsetLeft);
|
||||
|
||||
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
|
||||
float fps = wm.getDefaultDisplay().getRefreshRate();
|
||||
@@ -720,6 +710,7 @@ public class FlutterView
|
||||
|
||||
private boolean mAccessibilityEnabled = false;
|
||||
private boolean mTouchExplorationEnabled = false;
|
||||
private int mAccessibilityFeatureFlags = 0;
|
||||
private TouchExplorationListener mTouchExplorationListener;
|
||||
|
||||
protected void dispatchSemanticsAction(int id, AccessibilityBridge.Action action) {
|
||||
@@ -727,7 +718,8 @@ public class FlutterView
|
||||
}
|
||||
|
||||
protected void dispatchSemanticsAction(int id, AccessibilityBridge.Action action, Object args) {
|
||||
if (!isAttached()) return;
|
||||
if (!isAttached())
|
||||
return;
|
||||
ByteBuffer encodedArgs = null;
|
||||
int position = 0;
|
||||
if (args != null) {
|
||||
@@ -742,12 +734,19 @@ public class FlutterView
|
||||
super.onAttachedToWindow();
|
||||
mAccessibilityEnabled = mAccessibilityManager.isEnabled();
|
||||
mTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
Uri transitionUri = Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE);
|
||||
getContext().getContentResolver().registerContentObserver(transitionUri, false, mAnimationScaleObserver);
|
||||
}
|
||||
|
||||
if (mAccessibilityEnabled || mTouchExplorationEnabled) {
|
||||
ensureAccessibilityEnabled();
|
||||
}
|
||||
if (mTouchExplorationEnabled) {
|
||||
nativeSetAssistiveTechnologyEnabled(mNativeView.get(), true);
|
||||
mAccessibilityFeatureFlags ^= AccessibilityFeature.ACCESSIBLE_NAVIGATION.value;
|
||||
}
|
||||
// Apply additional accessibility settings
|
||||
updateAccessibilityFeatures();
|
||||
resetWillNotDraw();
|
||||
mAccessibilityManager.addAccessibilityStateChangeListener(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
@@ -758,13 +757,26 @@ public class FlutterView
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAccessibilityFeatures() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
String transitionAnimationScale = Settings.Global.getString(getContext().getContentResolver(),
|
||||
Settings.Global.TRANSITION_ANIMATION_SCALE);
|
||||
if (transitionAnimationScale != null && transitionAnimationScale.equals("0")) {
|
||||
mAccessibilityFeatureFlags ^= AccessibilityFeature.DISABLE_ANIMATIONS.value;
|
||||
} else {
|
||||
mAccessibilityFeatureFlags &= ~AccessibilityFeature.DISABLE_ANIMATIONS.value;
|
||||
}
|
||||
}
|
||||
nativeSetAccessibilityFeatures(mNativeView.get(), mAccessibilityFeatureFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
getContext().getContentResolver().unregisterContentObserver(mAnimationScaleObserver);
|
||||
mAccessibilityManager.removeAccessibilityStateChangeListener(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
mAccessibilityManager.removeTouchExplorationStateChangeListener(
|
||||
mTouchExplorationListener);
|
||||
mAccessibilityManager.removeTouchExplorationStateChangeListener(mTouchExplorationListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,20 +802,59 @@ public class FlutterView
|
||||
resetWillNotDraw();
|
||||
}
|
||||
|
||||
class TouchExplorationListener
|
||||
implements AccessibilityManager.TouchExplorationStateChangeListener {
|
||||
/// Must match the enum defined in window.dart.
|
||||
private enum AccessibilityFeature {
|
||||
ACCESSIBLE_NAVIGATION(1 << 0),
|
||||
INVERT_COLORS(1 << 1), // NOT SUPPORTED
|
||||
DISABLE_ANIMATIONS(1 << 2);
|
||||
|
||||
AccessibilityFeature(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
final int value;
|
||||
}
|
||||
|
||||
// Listens to the global TRANSITION_ANIMATION_SCALE property and notifies us so
|
||||
// that we can disable animations in Flutter.
|
||||
private class AnimationScaleObserver extends ContentObserver {
|
||||
public AnimationScaleObserver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
this.onChange(selfChange, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
String value = Settings.Global.getString(getContext().getContentResolver(),
|
||||
Settings.Global.TRANSITION_ANIMATION_SCALE);
|
||||
if (value == "0") {
|
||||
mAccessibilityFeatureFlags ^= AccessibilityFeature.DISABLE_ANIMATIONS.value;
|
||||
} else {
|
||||
mAccessibilityFeatureFlags &= ~AccessibilityFeature.DISABLE_ANIMATIONS.value;
|
||||
}
|
||||
nativeSetAccessibilityFeatures(mNativeView.get(), mAccessibilityFeatureFlags);
|
||||
}
|
||||
}
|
||||
|
||||
class TouchExplorationListener implements AccessibilityManager.TouchExplorationStateChangeListener {
|
||||
@Override
|
||||
public void onTouchExplorationStateChanged(boolean enabled) {
|
||||
if (enabled) {
|
||||
mTouchExplorationEnabled = true;
|
||||
ensureAccessibilityEnabled();
|
||||
nativeSetAssistiveTechnologyEnabled(mNativeView.get(), true);
|
||||
mAccessibilityFeatureFlags ^= AccessibilityFeature.ACCESSIBLE_NAVIGATION.value;
|
||||
nativeSetAccessibilityFeatures(mNativeView.get(), mAccessibilityFeatureFlags);
|
||||
} else {
|
||||
mTouchExplorationEnabled = false;
|
||||
if (mAccessibilityNodeProvider != null) {
|
||||
mAccessibilityNodeProvider.handleTouchExplorationExit();
|
||||
}
|
||||
nativeSetAssistiveTechnologyEnabled(mNativeView.get(), false);
|
||||
mAccessibilityFeatureFlags &= ~AccessibilityFeature.ACCESSIBLE_NAVIGATION.value;
|
||||
nativeSetAccessibilityFeatures(mNativeView.get(), mAccessibilityFeatureFlags);
|
||||
}
|
||||
resetWillNotDraw();
|
||||
}
|
||||
@@ -811,8 +862,10 @@ public class FlutterView
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeProvider getAccessibilityNodeProvider() {
|
||||
if (mAccessibilityEnabled) return mAccessibilityNodeProvider;
|
||||
// TODO(goderbauer): when a11y is off this should return a one-off snapshot of the a11y
|
||||
if (mAccessibilityEnabled)
|
||||
return mAccessibilityNodeProvider;
|
||||
// TODO(goderbauer): when a11y is off this should return a one-off snapshot of
|
||||
// the a11y
|
||||
// tree.
|
||||
return null;
|
||||
}
|
||||
@@ -820,7 +873,8 @@ public class FlutterView
|
||||
private AccessibilityBridge mAccessibilityNodeProvider;
|
||||
|
||||
void ensureAccessibilityEnabled() {
|
||||
if (!isAttached()) return;
|
||||
if (!isAttached())
|
||||
return;
|
||||
mAccessibilityEnabled = true;
|
||||
if (mAccessibilityNodeProvider == null) {
|
||||
mAccessibilityNodeProvider = new AccessibilityBridge(this);
|
||||
@@ -839,8 +893,7 @@ public class FlutterView
|
||||
if (!mTouchExplorationEnabled) {
|
||||
return false;
|
||||
}
|
||||
if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER
|
||||
|| event.getAction() == MotionEvent.ACTION_HOVER_MOVE) {
|
||||
if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER || event.getAction() == MotionEvent.ACTION_HOVER_MOVE) {
|
||||
mAccessibilityNodeProvider.handleTouchExploration(event.getX(), event.getY());
|
||||
} else if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
|
||||
mAccessibilityNodeProvider.handleTouchExplorationExit();
|
||||
@@ -873,9 +926,9 @@ public class FlutterView
|
||||
/**
|
||||
* Broadcast receiver used to discover active Flutter instances.
|
||||
*
|
||||
* This is used by the `flutter` tool to find the observatory ports
|
||||
* for all the active Flutter views. We dump the data to the logs
|
||||
* and the tool scrapes the log lines for the data.
|
||||
* This is used by the `flutter` tool to find the observatory ports for all the
|
||||
* active Flutter views. We dump the data to the logs and the tool scrapes the
|
||||
* log lines for the data.
|
||||
*/
|
||||
private class DiscoveryReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
@@ -893,16 +946,19 @@ public class FlutterView
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener will be called on the Android UI thread once when Flutter renders the first frame.
|
||||
* Listener will be called on the Android UI thread once when Flutter renders
|
||||
* the first frame.
|
||||
*/
|
||||
public interface FirstFrameListener { void onFirstFrame(); }
|
||||
public interface FirstFrameListener {
|
||||
void onFirstFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegistry.SurfaceTextureEntry createSurfaceTexture() {
|
||||
final SurfaceTexture surfaceTexture = new SurfaceTexture(0);
|
||||
surfaceTexture.detachFromGLContext();
|
||||
final SurfaceTextureRegistryEntry entry =
|
||||
new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(), surfaceTexture);
|
||||
final SurfaceTextureRegistryEntry entry = new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(),
|
||||
surfaceTexture);
|
||||
nativeRegisterTexture(mNativeView.get(), entry.id(), surfaceTexture);
|
||||
return entry;
|
||||
}
|
||||
@@ -915,14 +971,12 @@ public class FlutterView
|
||||
SurfaceTextureRegistryEntry(long id, SurfaceTexture surfaceTexture) {
|
||||
this.id = id;
|
||||
this.surfaceTexture = surfaceTexture;
|
||||
this.surfaceTexture.setOnFrameAvailableListener(
|
||||
new SurfaceTexture.OnFrameAvailableListener() {
|
||||
@Override
|
||||
public void onFrameAvailable(SurfaceTexture texture) {
|
||||
nativeMarkTextureFrameAvailable(
|
||||
mNativeView.get(), SurfaceTextureRegistryEntry.this.id);
|
||||
}
|
||||
});
|
||||
this.surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
|
||||
@Override
|
||||
public void onFrameAvailable(SurfaceTexture texture) {
|
||||
nativeMarkTextureFrameAvailable(mNativeView.get(), SurfaceTextureRegistryEntry.this.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -443,12 +443,11 @@ static void SetSemanticsEnabled(JNIEnv* env,
|
||||
ANDROID_SHELL_HOLDER->GetPlatformView()->SetSemanticsEnabled(enabled);
|
||||
}
|
||||
|
||||
static void SetAssistiveTechnologyEnabled(JNIEnv* env,
|
||||
jobject jcaller,
|
||||
jlong shell_holder,
|
||||
jboolean enabled) {
|
||||
ANDROID_SHELL_HOLDER->GetPlatformView()->SetAssistiveTechnologyEnabled(
|
||||
enabled);
|
||||
static void SetAccessibilityFeatures(JNIEnv* env,
|
||||
jobject jcaller,
|
||||
jlong shell_holder,
|
||||
jint flags) {
|
||||
ANDROID_SHELL_HOLDER->GetPlatformView()->SetAccessibilityFeatures(flags);
|
||||
}
|
||||
|
||||
static jboolean GetIsSoftwareRendering(JNIEnv* env, jobject jcaller) {
|
||||
@@ -623,10 +622,9 @@ bool PlatformViewAndroid::Register(JNIEnv* env) {
|
||||
.fnPtr = reinterpret_cast<void*>(&shell::SetSemanticsEnabled),
|
||||
},
|
||||
{
|
||||
.name = "nativeSetAssistiveTechnologyEnabled",
|
||||
.signature = "(JZ)V",
|
||||
.fnPtr =
|
||||
reinterpret_cast<void*>(&shell::SetAssistiveTechnologyEnabled),
|
||||
.name = "nativeSetAccessibilityFeatures",
|
||||
.signature = "(JI)V",
|
||||
.fnPtr = reinterpret_cast<void*>(&shell::SetAccessibilityFeatures),
|
||||
},
|
||||
{
|
||||
.name = "nativeGetIsSoftwareRenderingEnabled",
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
nibName:(NSString*)nibNameOrNil
|
||||
bundle:(NSBundle*)nibBundleOrNil {
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
|
||||
if (self) {
|
||||
if (projectOrNil == nil)
|
||||
_dartProject.reset([[FlutterDartProject alloc] init]);
|
||||
@@ -282,6 +281,16 @@
|
||||
name:UIAccessibilitySpeakScreenStatusDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[center addObserver:self
|
||||
selector:@selector(onAccessibilityStatusChanged:)
|
||||
name:UIAccessibilityInvertColorsStatusDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[center addObserver:self
|
||||
selector:@selector(onAccessibilityStatusChanged:)
|
||||
name:UIAccessibilityReduceMotionStatusDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[center addObserver:self
|
||||
selector:@selector(onMemoryWarning:)
|
||||
name:UIApplicationDidReceiveMemoryWarningNotification
|
||||
@@ -793,16 +802,23 @@ static inline blink::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* to
|
||||
|
||||
- (void)onAccessibilityStatusChanged:(NSNotification*)notification {
|
||||
auto platformView = _shell->GetPlatformView();
|
||||
int32_t flags = 0;
|
||||
if (UIAccessibilityIsInvertColorsEnabled())
|
||||
flags ^= static_cast<int32_t>(blink::AccessibilityFeatureFlag::kInvertColors);
|
||||
if (UIAccessibilityIsReduceMotionEnabled())
|
||||
flags ^= static_cast<int32_t>(blink::AccessibilityFeatureFlag::kDisableAnimations);
|
||||
#if TARGET_OS_SIMULATOR
|
||||
// There doesn't appear to be any way to determine whether the accessibility
|
||||
// inspector is enabled on the simulator. We conservatively always turn on the
|
||||
// accessibility bridge in the simulator, but never assistive technology.
|
||||
platformView->SetSemanticsEnabled(true);
|
||||
platformView->SetAssistiveTechnologyEnabled(false);
|
||||
platformView->SetAccessibilityFeatures(flags);
|
||||
#else
|
||||
bool enabled = UIAccessibilityIsVoiceOverRunning() || UIAccessibilityIsSwitchControlRunning();
|
||||
if (UIAccessibilityIsVoiceOverRunning() || UIAccessibilityIsSwitchControlRunning())
|
||||
flags ^= static_cast<int32_t>(blink::AccessibilityFeatureFlag::kAccessibleNavigation);
|
||||
platformView->SetSemanticsEnabled(enabled || UIAccessibilityIsSpeakScreenEnabled());
|
||||
platformView->SetAssistiveTechnologyEnabled(enabled);
|
||||
platformView->SetAccessibilityFeatures(flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class PlatformViewIOS final : public HeadlessPlatformViewIOS {
|
||||
void SetSemanticsEnabled(bool enabled) override;
|
||||
|
||||
// |shell::PlatformView|
|
||||
void SetAssistiveTechnologyEnabled(bool enabled) override;
|
||||
void SetAccessibilityFeatures(int32_t flags) override;
|
||||
|
||||
// |shell::PlatformView|
|
||||
void UpdateSemantics(
|
||||
|
||||
@@ -68,14 +68,8 @@ void PlatformViewIOS::SetSemanticsEnabled(bool enabled) {
|
||||
}
|
||||
|
||||
// |shell:PlatformView|
|
||||
void PlatformViewIOS::SetAssistiveTechnologyEnabled(bool enabled) {
|
||||
if (enabled && !accessibility_bridge_) {
|
||||
accessibility_bridge_ = std::make_unique<AccessibilityBridge>(owner_view_, this);
|
||||
}
|
||||
// Note: since the accessibility bridge is needed for both semantics and
|
||||
// assistive technologies, but you cannot have the latter without the
|
||||
// former, we only destroy the bridge in SetSemanticsEnabled and not here.
|
||||
PlatformView::SetAssistiveTechnologyEnabled(enabled);
|
||||
void PlatformViewIOS::SetAccessibilityFeatures(int32_t flags) {
|
||||
PlatformView::SetAccessibilityFeatures(flags);
|
||||
}
|
||||
|
||||
// |shell::PlatformView|
|
||||
|
||||
Reference in New Issue
Block a user