Revert "Implementing TextScaler for nonlinear text scaling" (flutter/engine#44882)
Reverts flutter/engine#42062 Failing due to: >>>>>>>> 08-18 15:59:41.350 3439 3484 E flutter : [ERROR:flutter/shell/platform/android/platform_view_android_jni_impl.cc(902)] Could not locate FlutterJNI#getScaledFontSize method >>>>>>>> 08-18 15:59:41.350 3439 3484 F flutter : [FATAL:flutter/shell/platform/android/library_loader.cc(26)] Check failed: result.
This commit is contained in:
@@ -110,7 +110,6 @@ typedef CanvasPath Path;
|
||||
V(PlatformConfigurationNativeApi::GetRootIsolateToken, 0) \
|
||||
V(PlatformConfigurationNativeApi::RegisterBackgroundIsolate, 1) \
|
||||
V(PlatformConfigurationNativeApi::SendPortPlatformMessage, 4) \
|
||||
V(PlatformConfigurationNativeApi::GetScaledFontSize, 2) \
|
||||
V(DartRuntimeHooks::Logger_PrintDebugString, 1) \
|
||||
V(DartRuntimeHooks::Logger_PrintString, 1) \
|
||||
V(DartRuntimeHooks::ScheduleMicrotask, 1) \
|
||||
|
||||
@@ -1050,19 +1050,17 @@ class PlatformDispatcher {
|
||||
if (brieflyShowPassword != null) {
|
||||
_brieflyShowPassword = brieflyShowPassword;
|
||||
}
|
||||
final Brightness platformBrightness = switch (data['platformBrightness']) {
|
||||
'dark' => Brightness.dark,
|
||||
'light' => Brightness.light,
|
||||
final Object? value => throw StateError('$value is not a valid platformBrightness.'),
|
||||
};
|
||||
final Brightness platformBrightness =
|
||||
data['platformBrightness']! as String == 'dark' ? Brightness.dark : Brightness.light;
|
||||
final String? systemFontFamily = data['systemFontFamily'] as String?;
|
||||
final int? configurationId = data['configurationId'] as int?;
|
||||
final _PlatformConfiguration previousConfiguration = _configuration;
|
||||
final bool platformBrightnessChanged = previousConfiguration.platformBrightness != platformBrightness;
|
||||
final bool textScaleFactorChanged = previousConfiguration.textScaleFactor != textScaleFactor;
|
||||
final bool alwaysUse24HourFormatChanged = previousConfiguration.alwaysUse24HourFormat != alwaysUse24HourFormat;
|
||||
final bool systemFontFamilyChanged = previousConfiguration.systemFontFamily != systemFontFamily;
|
||||
if (!platformBrightnessChanged && !textScaleFactorChanged && !alwaysUse24HourFormatChanged && !systemFontFamilyChanged && configurationId == null) {
|
||||
final bool alwaysUse24HourFormatChanged =
|
||||
previousConfiguration.alwaysUse24HourFormat != alwaysUse24HourFormat;
|
||||
final bool systemFontFamilyChanged =
|
||||
previousConfiguration.systemFontFamily != systemFontFamily;
|
||||
if (!platformBrightnessChanged && !textScaleFactorChanged && !alwaysUse24HourFormatChanged && !systemFontFamilyChanged) {
|
||||
return;
|
||||
}
|
||||
_configuration = previousConfiguration.copyWith(
|
||||
@@ -1070,11 +1068,9 @@ class PlatformDispatcher {
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat,
|
||||
platformBrightness: platformBrightness,
|
||||
systemFontFamily: systemFontFamily,
|
||||
configurationId: configurationId,
|
||||
);
|
||||
_invoke(onPlatformConfigurationChanged, _onPlatformConfigurationChangedZone);
|
||||
if (textScaleFactorChanged) {
|
||||
_cachedFontSizes = null;
|
||||
_invoke(onTextScaleFactorChanged, _onTextScaleFactorChangedZone);
|
||||
}
|
||||
if (platformBrightnessChanged) {
|
||||
@@ -1247,99 +1243,6 @@ class PlatformDispatcher {
|
||||
|
||||
@Native<Handle Function()>(symbol: 'PlatformConfigurationNativeApi::DefaultRouteName')
|
||||
external static String _defaultRouteName();
|
||||
|
||||
/// Computes the scaled font size from the given `unscaledFontSize`, according
|
||||
/// to the user's platform preferences.
|
||||
///
|
||||
/// Many platforms allow users to scale text globally for better readability.
|
||||
/// Given the font size the app developer specified in logical pixels, this
|
||||
/// method converts it to the preferred font size (also in logical pixels) that
|
||||
/// accounts for platform-wide text scaling. The return value is always
|
||||
/// non-negative.
|
||||
///
|
||||
/// The scaled value of the same font size input may change if the user changes
|
||||
/// the text scaling preference (in system settings for example). The
|
||||
/// [onTextScaleFactorChanged] callback can be used to monitor such changes.
|
||||
///
|
||||
/// Instead of directly calling this method, applications should typically use
|
||||
/// [MediaQuery.textScalerOf] to retrive the scaled font size in a widget tree,
|
||||
/// so text in the app resizes properly when the text scaling preference
|
||||
/// changes.
|
||||
double scaleFontSize(double unscaledFontSize) {
|
||||
assert(unscaledFontSize >= 0);
|
||||
assert(unscaledFontSize.isFinite);
|
||||
|
||||
if (textScaleFactor == 1.0) {
|
||||
return unscaledFontSize;
|
||||
}
|
||||
|
||||
final int unscaledFloor = unscaledFontSize.floor();
|
||||
final int unscaledCeil = unscaledFontSize.ceil();
|
||||
if (unscaledFloor == unscaledCeil) {
|
||||
// No need to interpolate if the input value is an integer.
|
||||
return _scaleAndMemoize(unscaledFloor) ?? unscaledFontSize * textScaleFactor;
|
||||
}
|
||||
assert(unscaledCeil - unscaledFloor == 1, 'Unexpected interpolation range: $unscaledFloor - $unscaledCeil.');
|
||||
|
||||
return switch ((_scaleAndMemoize(unscaledFloor), _scaleAndMemoize(unscaledCeil))) {
|
||||
(null, _) || (_, null) => unscaledFontSize * textScaleFactor,
|
||||
(final double lower, final double upper) => lower + (upper - lower) * (unscaledFontSize - unscaledFloor),
|
||||
};
|
||||
}
|
||||
|
||||
// The cache is cleared when the text scale factor changes.
|
||||
Map<int, double>? _cachedFontSizes;
|
||||
// This method returns null if an error is encountered.
|
||||
double? _scaleAndMemoize(int unscaledFontSize) {
|
||||
final int? configurationId = _configuration.configurationId;
|
||||
if (configurationId == null) {
|
||||
// The platform uses linear scaling, or the platform hasn't sent us a
|
||||
// configuration yet.
|
||||
return null;
|
||||
}
|
||||
final double? cachedValue = _cachedFontSizes?[unscaledFontSize];
|
||||
if (cachedValue != null) {
|
||||
assert(cachedValue >= 0);
|
||||
return cachedValue;
|
||||
}
|
||||
|
||||
final double unscaledFontSizeDouble = unscaledFontSize.toDouble();
|
||||
final double fontSize = PlatformDispatcher._getScaledFontSize(unscaledFontSizeDouble, configurationId);
|
||||
if (fontSize >= 0) {
|
||||
return (_cachedFontSizes ??= <int, double>{})[unscaledFontSize] = fontSize;
|
||||
}
|
||||
switch (fontSize) {
|
||||
case -1:
|
||||
// Invalid configuration id. This error can be unrecoverable as the
|
||||
// _getScaledFontSize function can be destructive.
|
||||
assert(false, 'Flutter Error: incorrect configuration id: $configurationId.');
|
||||
case final double errorCode:
|
||||
assert(false, 'Unknown error: GetScaledFontSize failed with $errorCode.');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Calls the platform's text scaling implementation to scale the given
|
||||
// `unscaledFontSize`.
|
||||
//
|
||||
// The `configurationId` parameter tells the embedder which platform
|
||||
// configuration to use for computing the scaled font size. When the user
|
||||
// changes the platform configuration, the configuration data will first be
|
||||
// made available on the platform thread before being dispatched asynchronously
|
||||
// to the Flutter UI thread. Since this call is synchronous, without this
|
||||
// identifier, it could call into the embber who's using a newer configuration
|
||||
// that Flutter has not received yet. The `configurationId` parameter must be
|
||||
// the lastest configuration id received from the platform
|
||||
// (`_configuration.configurationId`). Using an incorrect id could result in
|
||||
// an unrecoverable error.
|
||||
//
|
||||
// Currently this is only implemented on newer versions of Android (SDK level
|
||||
// 34, using the `TypedValue#applyDimension` API). Platforms that do not have
|
||||
// the capability will never send a `configurationId` to [PlatformDispatcher],
|
||||
// and should not call this method. This method returns -1 when the specified
|
||||
// configurationId does not match any configuration.
|
||||
@Native<Double Function(Double, Int)>(symbol: 'PlatformConfigurationNativeApi::GetScaledFontSize')
|
||||
external static double _getScaledFontSize(double unscaledFontSize, int configurationId);
|
||||
}
|
||||
|
||||
/// Configuration of the platform.
|
||||
@@ -1355,7 +1258,6 @@ class _PlatformConfiguration {
|
||||
this.locales = const <Locale>[],
|
||||
this.defaultRouteName,
|
||||
this.systemFontFamily,
|
||||
this.configurationId,
|
||||
});
|
||||
|
||||
_PlatformConfiguration copyWith({
|
||||
@@ -1367,7 +1269,6 @@ class _PlatformConfiguration {
|
||||
List<Locale>? locales,
|
||||
String? defaultRouteName,
|
||||
String? systemFontFamily,
|
||||
int? configurationId,
|
||||
}) {
|
||||
return _PlatformConfiguration(
|
||||
accessibilityFeatures: accessibilityFeatures ?? this.accessibilityFeatures,
|
||||
@@ -1378,7 +1279,6 @@ class _PlatformConfiguration {
|
||||
locales: locales ?? this.locales,
|
||||
defaultRouteName: defaultRouteName ?? this.defaultRouteName,
|
||||
systemFontFamily: systemFontFamily ?? this.systemFontFamily,
|
||||
configurationId: configurationId ?? this.configurationId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1410,22 +1310,6 @@ class _PlatformConfiguration {
|
||||
|
||||
/// The system-reported default font family.
|
||||
final String? systemFontFamily;
|
||||
|
||||
/// A unique identifier for this [_PlatformConfiguration].
|
||||
///
|
||||
/// This unique identifier is optionally assigned by the platform embedder.
|
||||
/// Dart code that runs on the Flutter UI thread and synchronously invokes
|
||||
/// platform APIs can use this identifier to tell the embedder to use the
|
||||
/// configuration that matches the current [_PlatformConfiguration] in
|
||||
/// dart:ui. See the [_getScaledFontSize] function for an example.
|
||||
///
|
||||
/// This field's nullability also indicates whether the platform supports
|
||||
/// nonlinear text scaling (as it's the only feature that requires synchronous
|
||||
/// invocation of platform APIs). This field is always null if the platform
|
||||
/// does not use nonlinear text scaling, or when dart:ui has not received any
|
||||
/// configuration updates from the embedder yet. The _getScaledFontSize
|
||||
/// function should not be called in either case.
|
||||
final int? configurationId;
|
||||
}
|
||||
|
||||
/// An immutable view configuration.
|
||||
|
||||
@@ -631,13 +631,4 @@ void PlatformConfigurationNativeApi::RegisterBackgroundIsolate(
|
||||
dart_state->SetPlatformMessageHandler(weak_platform_message_handler);
|
||||
}
|
||||
|
||||
double PlatformConfigurationNativeApi::GetScaledFontSize(
|
||||
double unscaled_font_size,
|
||||
int configuration_id) {
|
||||
UIDartState::ThrowIfUIOperationsProhibited();
|
||||
return UIDartState::Current()
|
||||
->platform_configuration()
|
||||
->client()
|
||||
->GetScaledFontSize(unscaled_font_size, configuration_id);
|
||||
}
|
||||
} // namespace flutter
|
||||
|
||||
@@ -207,28 +207,6 @@ class PlatformConfigurationClient {
|
||||
///
|
||||
virtual void RequestDartDeferredLibrary(intptr_t loading_unit_id) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// @brief Synchronously invokes platform-specific APIs to apply the
|
||||
/// system text scaling on the given unscaled font size.
|
||||
///
|
||||
/// Platforms that support this feature (currently it's only
|
||||
/// implemented for Android SDK level 34+) will send a valid
|
||||
/// configuration_id to potential callers, before this method can
|
||||
/// be called.
|
||||
///
|
||||
/// @param[in] unscaled_font_size The unscaled font size specified by the
|
||||
/// app developer. The value is in logical
|
||||
/// pixels, and is guaranteed to be finite and
|
||||
/// non-negative.
|
||||
/// @param[in] configuration_id The unique id of the configuration to use
|
||||
/// for computing the scaled font size.
|
||||
///
|
||||
/// @return The scaled font size in logical pixels, or -1 if the given
|
||||
/// configuration_id did not match a valid configuration.
|
||||
///
|
||||
virtual double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const = 0;
|
||||
|
||||
protected:
|
||||
virtual ~PlatformConfigurationClient();
|
||||
};
|
||||
@@ -598,9 +576,6 @@ class PlatformConfigurationNativeApi {
|
||||
|
||||
static void RegisterBackgroundIsolate(int64_t root_isolate_token);
|
||||
|
||||
static double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id);
|
||||
|
||||
private:
|
||||
static Dart_PerformanceMode current_performance_mode_;
|
||||
};
|
||||
|
||||
@@ -146,8 +146,6 @@ abstract class PlatformDispatcher {
|
||||
|
||||
VoidCallback? get onFrameDataChanged => null;
|
||||
set onFrameDataChanged(VoidCallback? callback) {}
|
||||
|
||||
double scaleFontSize(double unscaledFontSize);
|
||||
}
|
||||
|
||||
enum FramePhase {
|
||||
|
||||
@@ -1287,9 +1287,6 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
|
||||
|
||||
@override
|
||||
ui.FrameData get frameData => const ui.FrameData.webOnly();
|
||||
|
||||
@override
|
||||
double scaleFontSize(double unscaledFontSize) => unscaledFontSize * textScaleFactor;
|
||||
}
|
||||
|
||||
bool _handleWebTestEnd2EndMessage(MethodCodec codec, ByteData? data) {
|
||||
|
||||
@@ -545,11 +545,6 @@ bool RuntimeController::SetDisplays(const std::vector<DisplayData>& displays) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double RuntimeController::GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const {
|
||||
return client_.GetScaledFontSize(unscaled_font_size, configuration_id);
|
||||
}
|
||||
|
||||
RuntimeController::Locale::Locale(std::string language_code_,
|
||||
std::string country_code_,
|
||||
std::string script_code_,
|
||||
|
||||
@@ -683,10 +683,6 @@ class RuntimeController : public PlatformConfigurationClient {
|
||||
std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocale(
|
||||
const std::vector<std::string>& supported_locale_data) override;
|
||||
|
||||
// |PlatformConfigurationClient|
|
||||
double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(RuntimeController);
|
||||
};
|
||||
|
||||
|
||||
@@ -54,9 +54,6 @@ class RuntimeDelegate {
|
||||
virtual std::weak_ptr<PlatformMessageHandler> GetPlatformMessageHandler()
|
||||
const = 0;
|
||||
|
||||
virtual double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const = 0;
|
||||
|
||||
protected:
|
||||
virtual ~RuntimeDelegate();
|
||||
};
|
||||
|
||||
@@ -500,11 +500,6 @@ std::unique_ptr<std::vector<std::string>> Engine::ComputePlatformResolvedLocale(
|
||||
return delegate_.ComputePlatformResolvedLocale(supported_locale_data);
|
||||
}
|
||||
|
||||
double Engine::GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const {
|
||||
return delegate_.GetScaledFontSize(unscaled_font_size, configuration_id);
|
||||
}
|
||||
|
||||
void Engine::SetNeedsReportTimings(bool needs_reporting) {
|
||||
delegate_.SetNeedsReportTimings(needs_reporting);
|
||||
}
|
||||
|
||||
@@ -293,28 +293,6 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
/// Flutter to the host platform (and its responses).
|
||||
virtual const std::shared_ptr<PlatformMessageHandler>&
|
||||
GetPlatformMessageHandler() const = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// @brief Synchronously invokes platform-specific APIs to apply the
|
||||
/// system text scaling on the given unscaled font size.
|
||||
///
|
||||
/// Platforms that support this feature (currently it's only
|
||||
/// implemented for Android SDK level 34+) will send a valid
|
||||
/// configuration_id to potential callers, before this method
|
||||
/// can be called.
|
||||
///
|
||||
/// @param[in] unscaled_font_size The unscaled font size specified by the
|
||||
/// app developer. The value is in logical
|
||||
/// pixels, and is guaranteed to be finite
|
||||
/// and non-negative.
|
||||
/// @param[in] configuration_id The unique id of the configuration to
|
||||
/// use for computing the scaled font size.
|
||||
///
|
||||
/// @return The scaled font size in logical pixels, or -1 when the given
|
||||
/// configuration_id did not match a valid configuration.
|
||||
///
|
||||
virtual double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const = 0;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -977,10 +955,6 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
std::weak_ptr<PlatformMessageHandler> GetPlatformMessageHandler()
|
||||
const override;
|
||||
|
||||
// |RuntimeDelegate|
|
||||
double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const override;
|
||||
|
||||
void SetNeedsReportTimings(bool value) override;
|
||||
|
||||
bool HandleLifecyclePlatformMessage(PlatformMessage* message);
|
||||
|
||||
@@ -39,8 +39,6 @@ class MockDelegate : public Engine::Delegate {
|
||||
MOCK_METHOD0(GetCurrentTimePoint, fml::TimePoint());
|
||||
MOCK_CONST_METHOD0(GetPlatformMessageHandler,
|
||||
const std::shared_ptr<PlatformMessageHandler>&());
|
||||
MOCK_CONST_METHOD2(GetScaledFontSize,
|
||||
double(double font_size, int configuration_id));
|
||||
};
|
||||
|
||||
class MockResponse : public PlatformMessageResponse {
|
||||
@@ -69,8 +67,6 @@ class MockRuntimeDelegate : public RuntimeDelegate {
|
||||
MOCK_METHOD1(RequestDartDeferredLibrary, void(intptr_t));
|
||||
MOCK_CONST_METHOD0(GetPlatformMessageHandler,
|
||||
std::weak_ptr<PlatformMessageHandler>());
|
||||
MOCK_CONST_METHOD2(GetScaledFontSize,
|
||||
double(double font_size, int configuration_id));
|
||||
};
|
||||
|
||||
class MockRuntimeController : public RuntimeController {
|
||||
|
||||
@@ -199,12 +199,4 @@ const Settings& PlatformView::GetSettings() const {
|
||||
return delegate_.OnPlatformViewGetSettings();
|
||||
}
|
||||
|
||||
double PlatformView::GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const {
|
||||
// Unreachable by default, as most platforms do not support nonlinear scaling
|
||||
// and the Flutter application never invokes this method.
|
||||
FML_UNREACHABLE();
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -833,28 +833,6 @@ class PlatformView {
|
||||
///
|
||||
const Settings& GetSettings() const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// @brief Synchronously invokes platform-specific APIs to apply the
|
||||
/// system text scaling on the given unscaled font size.
|
||||
///
|
||||
/// Platforms that support this feature (currently it's only
|
||||
/// implemented for Android SDK level 34+) will send a valid
|
||||
/// configuration_id to potential callers, before this method can
|
||||
/// be called.
|
||||
///
|
||||
/// @param[in] unscaled_font_size The unscaled font size specified by the
|
||||
/// app developer. The value is in logical
|
||||
/// pixels, and is guaranteed to be finite and
|
||||
/// non-negative.
|
||||
/// @param[in] configuration_id The unique id of the configuration to use
|
||||
/// for computing the scaled font size.
|
||||
///
|
||||
/// @return The scaled font size in logical pixels, or -1 if the given
|
||||
/// configuration_id did not match a valid configuration.
|
||||
///
|
||||
virtual double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const;
|
||||
|
||||
protected:
|
||||
// This is the only method called on the raster task runner.
|
||||
virtual std::unique_ptr<Surface> CreateRenderingSurface();
|
||||
|
||||
@@ -1478,13 +1478,6 @@ void Shell::RequestDartDeferredLibrary(intptr_t loading_unit_id) {
|
||||
});
|
||||
}
|
||||
|
||||
// |Engine::Delegate|
|
||||
double Shell::GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const {
|
||||
return platform_view_->GetScaledFontSize(unscaled_font_size,
|
||||
configuration_id);
|
||||
}
|
||||
|
||||
void Shell::ReportTimings() {
|
||||
FML_DCHECK(is_set_up_);
|
||||
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
|
||||
|
||||
@@ -680,10 +680,6 @@ class Shell final : public PlatformView::Delegate,
|
||||
// |Engine::Delegate|
|
||||
fml::TimePoint GetCurrentTimePoint() override;
|
||||
|
||||
// |Engine::Delegate|
|
||||
double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const override;
|
||||
|
||||
// |Rasterizer::Delegate|
|
||||
void OnFrameRasterized(const FrameTiming&) override;
|
||||
|
||||
|
||||
@@ -60,8 +60,6 @@ class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI {
|
||||
MOCK_METHOD0(GetDisplayHeight, double());
|
||||
MOCK_METHOD0(GetDisplayDensity, double());
|
||||
MOCK_METHOD1(RequestDartDeferredLibrary, bool(int loading_unit_id));
|
||||
MOCK_CONST_METHOD2(FlutterViewGetScaledFontSize,
|
||||
double(double font_size, int configuration_id));
|
||||
};
|
||||
|
||||
class MockPlatformMessageResponse : public PlatformMessageResponse {
|
||||
|
||||
@@ -1493,7 +1493,6 @@ public class FlutterView extends FrameLayout
|
||||
.getSettingsChannel()
|
||||
.startMessage()
|
||||
.setTextScaleFactor(getResources().getConfiguration().fontScale)
|
||||
.setDisplayMetrics(getResources().getDisplayMetrics())
|
||||
.setNativeSpellCheckServiceDefined(isNativeSpellCheckServiceDefined)
|
||||
.setBrieflyShowPassword(
|
||||
Settings.System.getInt(
|
||||
|
||||
@@ -12,9 +12,7 @@ import android.graphics.ImageDecoder;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Size;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import androidx.annotation.Keep;
|
||||
@@ -29,7 +27,6 @@ import io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager;
|
||||
import io.flutter.embedding.engine.mutatorsstack.FlutterMutatorsStack;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.embedding.engine.renderer.SurfaceTextureWrapper;
|
||||
import io.flutter.embedding.engine.systemchannels.SettingsChannel;
|
||||
import io.flutter.plugin.common.StandardMessageCodec;
|
||||
import io.flutter.plugin.localization.LocalizationPlugin;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
@@ -1307,20 +1304,6 @@ public class FlutterJNI {
|
||||
}
|
||||
|
||||
// ----- End Localization Support ----
|
||||
@Nullable
|
||||
public float getScaledFontSize(float fontSize, int configurationId) {
|
||||
final DisplayMetrics metrics = SettingsChannel.getPastDisplayMetrics(configurationId);
|
||||
if (metrics == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"getScaledFontSize called with configurationId "
|
||||
+ String.valueOf(configurationId)
|
||||
+ ", which can't be found.");
|
||||
return -1f;
|
||||
}
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, fontSize, metrics)
|
||||
/ metrics.density;
|
||||
}
|
||||
|
||||
// ----- Start Deferred Components Support ----
|
||||
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
package io.flutter.embedding.engine.systemchannels;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import io.flutter.plugin.common.BasicMessageChannel;
|
||||
import io.flutter.plugin.common.JSONMessageCodec;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class SettingsChannel {
|
||||
private static final String TAG = "SettingsChannel";
|
||||
@@ -24,10 +17,6 @@ public class SettingsChannel {
|
||||
private static final String BRIEFLY_SHOW_PASSWORD = "brieflyShowPassword";
|
||||
private static final String ALWAYS_USE_24_HOUR_FORMAT = "alwaysUse24HourFormat";
|
||||
private static final String PLATFORM_BRIGHTNESS = "platformBrightness";
|
||||
private static final String CONFIGURATION_ID = "configurationId";
|
||||
|
||||
// When hasNonlinearTextScalingSupport() returns false, this will not be initialized.
|
||||
private static final ConfigurationQueue CONFIGURATION_QUEUE = new ConfigurationQueue();
|
||||
|
||||
@NonNull public final BasicMessageChannel<Object> channel;
|
||||
|
||||
@@ -35,19 +24,6 @@ public class SettingsChannel {
|
||||
this.channel = new BasicMessageChannel<>(dartExecutor, CHANNEL_NAME, JSONMessageCodec.INSTANCE);
|
||||
}
|
||||
|
||||
@SuppressLint("AnnotateVersionCheck")
|
||||
public static boolean hasNonlinearTextScalingSupport() {
|
||||
return Build.VERSION.SDK_INT >= 34;
|
||||
}
|
||||
|
||||
// This method will only be called on Flutter's UI thread.
|
||||
public static DisplayMetrics getPastDisplayMetrics(int configId) {
|
||||
assert hasNonlinearTextScalingSupport();
|
||||
final ConfigurationQueue.SentConfiguration configuration =
|
||||
CONFIGURATION_QUEUE.getConfiguration(configId);
|
||||
return configuration == null ? null : configuration.displayMetrics;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MessageBuilder startMessage() {
|
||||
return new MessageBuilder(channel);
|
||||
@@ -56,18 +32,11 @@ public class SettingsChannel {
|
||||
public static class MessageBuilder {
|
||||
@NonNull private final BasicMessageChannel<Object> channel;
|
||||
@NonNull private Map<String, Object> message = new HashMap<>();
|
||||
@Nullable private DisplayMetrics displayMetrics;
|
||||
|
||||
MessageBuilder(@NonNull BasicMessageChannel<Object> channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MessageBuilder setDisplayMetrics(@NonNull DisplayMetrics displayMetrics) {
|
||||
this.displayMetrics = displayMetrics;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MessageBuilder setTextScaleFactor(float textScaleFactor) {
|
||||
message.put(TEXT_SCALE_FACTOR, textScaleFactor);
|
||||
@@ -111,17 +80,7 @@ public class SettingsChannel {
|
||||
+ "\n"
|
||||
+ "platformBrightness: "
|
||||
+ message.get(PLATFORM_BRIGHTNESS));
|
||||
final DisplayMetrics metrics = this.displayMetrics;
|
||||
if (!hasNonlinearTextScalingSupport() || metrics == null) {
|
||||
channel.send(message);
|
||||
return;
|
||||
}
|
||||
final ConfigurationQueue.SentConfiguration sentConfiguration =
|
||||
new ConfigurationQueue.SentConfiguration(metrics);
|
||||
final BasicMessageChannel.Reply deleteCallback =
|
||||
CONFIGURATION_QUEUE.enqueueConfiguration(sentConfiguration);
|
||||
message.put(CONFIGURATION_ID, sentConfiguration.generationNumber);
|
||||
channel.send(message, deleteCallback);
|
||||
channel.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,127 +100,4 @@ public class SettingsChannel {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A FIFO queue that maintains generations of configurations that are potentially used by the
|
||||
* Flutter application.
|
||||
*
|
||||
* <p>Platform configurations needed by the Flutter app (for example, text scale factor) are
|
||||
* retrived on the platform thread, serialized and sent to the Flutter application running on the
|
||||
* Flutter UI thread. However, configurations exposed as functions that take parameters are
|
||||
* typically not serializable. To allow the Flutter app to access these configurations, one
|
||||
* possible solution is to create dart bindings that allow the Flutter framework to invoke these
|
||||
* functions via JNI synchronously. To ensure the serialized configuration and these functions
|
||||
* represent the same set of configurations at any given time, a "generation" id is used in these
|
||||
* synchronous calls, to keep them consistent with the serialized configuration that the Flutter
|
||||
* app most recently received and is currently using.
|
||||
*
|
||||
* <p>A unique generation identifier is generated by the {@link SettingsChannel} and associated
|
||||
* with a configuration when it sends a serialized configuration to the Flutter framework. This
|
||||
* queue keeps different generations of configurations that could be used by the Flutter
|
||||
* framework, and cleans up old configurations that the Flutter framework no longer uses. When the
|
||||
* Flutter framework invokes a function to access the configuration with a generation identifier,
|
||||
* this queue finds the configuration with that identifier and also cleans up configurations that
|
||||
* are no longer needed.
|
||||
*
|
||||
* <p>This mechanism is only needed because {@code TypedValue#applyDimension} does not take the
|
||||
* current text scale factor as an input. Once the AndroidX API that allows us to query the scaled
|
||||
* font size with a pure function is available, we can scrap this class and make the
|
||||
* implementation much simpler.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static class ConfigurationQueue {
|
||||
private final ConcurrentLinkedQueue<SentConfiguration> sentQueue =
|
||||
new ConcurrentLinkedQueue<>();
|
||||
|
||||
// The current SentConfiguration the Flutter application is using, according
|
||||
// to the most recent getConfiguration call.
|
||||
//
|
||||
// This instance variable will only be accessed by getConfiguration, on
|
||||
// Flutter's UI thread.
|
||||
private SentConfiguration currentConfiguration;
|
||||
|
||||
/**
|
||||
* Returns the {@link SentConfiguration} associated with the given {@code configGeneration}, and
|
||||
* removes configurations older than the returned configurations from the queue as they are no
|
||||
* longer needed.
|
||||
*/
|
||||
public SentConfiguration getConfiguration(int configGeneration) {
|
||||
if (currentConfiguration == null) {
|
||||
currentConfiguration = sentQueue.poll();
|
||||
}
|
||||
|
||||
// Remove the older entries, up to the entry associated with
|
||||
// configGeneration. Here we assume the generationNumber never overflows.
|
||||
while (currentConfiguration != null
|
||||
&& currentConfiguration.generationNumber < configGeneration) {
|
||||
currentConfiguration = sentQueue.poll();
|
||||
}
|
||||
|
||||
if (currentConfiguration == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Cannot find config with generation: "
|
||||
+ String.valueOf(configGeneration)
|
||||
+ ", after exhausting the queue.");
|
||||
return null;
|
||||
} else if (currentConfiguration.generationNumber != configGeneration) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Cannot find config with generation: "
|
||||
+ String.valueOf(configGeneration)
|
||||
+ ", the oldest config is now: "
|
||||
+ String.valueOf(currentConfiguration.generationNumber));
|
||||
return null;
|
||||
}
|
||||
return currentConfiguration;
|
||||
}
|
||||
|
||||
private SentConfiguration previousEnqueuedConfiguration;
|
||||
|
||||
/**
|
||||
* Adds the most recently sent {@link SentConfiguration} to the queue.
|
||||
*
|
||||
* @return a {@link BasicMessageChannel.Reply} whose {@code reply} method must be called when
|
||||
* the embedder receives the reply for the sent configuration, to properly clean up older
|
||||
* configurations in the queue.
|
||||
*/
|
||||
@UiThread
|
||||
@Nullable
|
||||
public BasicMessageChannel.Reply enqueueConfiguration(SentConfiguration config) {
|
||||
sentQueue.add(config);
|
||||
final SentConfiguration configurationToRemove = previousEnqueuedConfiguration;
|
||||
previousEnqueuedConfiguration = config;
|
||||
return configurationToRemove == null
|
||||
? null
|
||||
: new BasicMessageChannel.Reply() {
|
||||
@UiThread
|
||||
@Override
|
||||
public void reply(Object reply) {
|
||||
// Removes the SentConfiguration sent right before `config`. Since
|
||||
// platform messages are also FIFO older messages will be removed
|
||||
// before newer ones.
|
||||
sentQueue.remove(configurationToRemove);
|
||||
if (!sentQueue.isEmpty()) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"The queue becomes empty after removing config generation "
|
||||
+ String.valueOf(configurationToRemove.generationNumber));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class SentConfiguration {
|
||||
private static int nextConfigGeneration = Integer.MIN_VALUE;
|
||||
|
||||
@NonNull public final int generationNumber;
|
||||
@NonNull private final DisplayMetrics displayMetrics;
|
||||
|
||||
public SentConfiguration(@NonNull DisplayMetrics displayMetrics) {
|
||||
this.generationNumber = nextConfigGeneration++;
|
||||
this.displayMetrics = displayMetrics;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,11 +123,6 @@ class JNIMock final : public PlatformViewAndroidJNI {
|
||||
RequestDartDeferredLibrary,
|
||||
(int loading_unit_id),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(double,
|
||||
FlutterViewGetScaledFontSize,
|
||||
(double font_size, int configuration_id),
|
||||
(const, override));
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -223,9 +223,6 @@ class PlatformViewAndroidJNI {
|
||||
virtual double GetDisplayDensity() = 0;
|
||||
|
||||
virtual bool RequestDartDeferredLibrary(int loading_unit_id) = 0;
|
||||
|
||||
virtual double FlutterViewGetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const = 0;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -472,9 +472,4 @@ void PlatformViewAndroid::FireFirstFrameCallback() {
|
||||
jni_facade_->FlutterViewOnFirstFrame();
|
||||
}
|
||||
|
||||
double PlatformViewAndroid::GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const {
|
||||
return jni_facade_->FlutterViewGetScaledFontSize(unscaled_font_size,
|
||||
configuration_id);
|
||||
}
|
||||
} // namespace flutter
|
||||
|
||||
@@ -175,9 +175,6 @@ class PlatformViewAndroid final : public PlatformView {
|
||||
|
||||
void FireFirstFrameCallback();
|
||||
|
||||
double GetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewAndroid);
|
||||
};
|
||||
} // namespace flutter
|
||||
|
||||
@@ -93,8 +93,6 @@ static jmethodID g_update_semantics_method = nullptr;
|
||||
|
||||
static jmethodID g_update_custom_accessibility_actions_method = nullptr;
|
||||
|
||||
static jmethodID g_get_scaled_font_size_method = nullptr;
|
||||
|
||||
static jmethodID g_on_first_frame_method = nullptr;
|
||||
|
||||
static jmethodID g_on_engine_restart_method = nullptr;
|
||||
@@ -895,14 +893,6 @@ bool RegisterApi(JNIEnv* env) {
|
||||
return false;
|
||||
}
|
||||
|
||||
g_get_scaled_font_size_method = env->GetMethodID(
|
||||
g_flutter_jni_class->obj(), "getScaledFontSize", "(FJ)F");
|
||||
|
||||
if (g_get_scaled_font_size_method == nullptr) {
|
||||
FML_LOG(ERROR) << "Could not locate FlutterJNI#getScaledFontSize method";
|
||||
return false;
|
||||
}
|
||||
|
||||
g_update_semantics_method = env->GetMethodID(
|
||||
g_flutter_jni_class->obj(), "updateSemantics",
|
||||
"(Ljava/nio/ByteBuffer;[Ljava/lang/String;[Ljava/nio/ByteBuffer;)V");
|
||||
@@ -1325,23 +1315,6 @@ void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessageResponse(
|
||||
FML_CHECK(fml::jni::CheckException(env));
|
||||
}
|
||||
|
||||
double PlatformViewAndroidJNIImpl::FlutterViewGetScaledFontSize(
|
||||
double font_size,
|
||||
int configuration_id) const {
|
||||
JNIEnv* env = fml::jni::AttachCurrentThread();
|
||||
|
||||
auto java_object = java_object_.get(env);
|
||||
if (java_object.is_null()) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
const jfloat scaledSize =
|
||||
env->CallFloatMethod(java_object.obj(), g_get_scaled_font_size_method,
|
||||
(jfloat)font_size, (jint)configuration_id);
|
||||
FML_CHECK(fml::jni::CheckException(env));
|
||||
return (double)scaledSize;
|
||||
}
|
||||
|
||||
void PlatformViewAndroidJNIImpl::FlutterViewUpdateSemantics(
|
||||
std::vector<uint8_t> buffer,
|
||||
std::vector<std::string> strings,
|
||||
|
||||
@@ -99,9 +99,6 @@ class PlatformViewAndroidJNIImpl final : public PlatformViewAndroidJNI {
|
||||
|
||||
bool RequestDartDeferredLibrary(int loading_unit_id) override;
|
||||
|
||||
double FlutterViewGetScaledFontSize(double unscaled_font_size,
|
||||
int configuration_id) const override;
|
||||
|
||||
private:
|
||||
// Reference to FlutterJNI object.
|
||||
const fml::jni::JavaObjectWeakGlobalRef java_object_;
|
||||
|
||||
@@ -1287,7 +1287,6 @@ public class FlutterActivityAndFragmentDelegateTest {
|
||||
when(fakeMessageBuilder.setPlatformBrightness(any(SettingsChannel.PlatformBrightness.class)))
|
||||
.thenReturn(fakeMessageBuilder);
|
||||
when(fakeMessageBuilder.setTextScaleFactor(any(Float.class))).thenReturn(fakeMessageBuilder);
|
||||
when(fakeMessageBuilder.setDisplayMetrics(any())).thenReturn(fakeMessageBuilder);
|
||||
when(fakeMessageBuilder.setNativeSpellCheckServiceDefined(any(Boolean.class)))
|
||||
.thenReturn(fakeMessageBuilder);
|
||||
when(fakeMessageBuilder.setBrieflyShowPassword(any(Boolean.class)))
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
package io.flutter.embedding.engine.systemchannels;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.isNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.util.DisplayMetrics;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import io.flutter.plugin.common.BasicMessageChannel;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@Config(manifest = Config.NONE)
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SettingsChannelTest {
|
||||
@Test
|
||||
@TargetApi(33)
|
||||
@Config(sdk = 33)
|
||||
public void setDisplayMetricsDoesNothingOnAPILevel33() {
|
||||
final DartExecutor executor = mock(DartExecutor.class);
|
||||
executor.onAttachedToJNI();
|
||||
final SettingsChannel settingsChannel = new SettingsChannel(executor);
|
||||
|
||||
final ArgumentCaptor<ByteBuffer> messageCaptor = ArgumentCaptor.forClass(ByteBuffer.class);
|
||||
|
||||
settingsChannel.startMessage().setDisplayMetrics(mock(DisplayMetrics.class)).send();
|
||||
|
||||
verify(executor).send(eq("flutter/settings"), messageCaptor.capture(), isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationQueueWorks() {
|
||||
final SettingsChannel.ConfigurationQueue queue = new SettingsChannel.ConfigurationQueue();
|
||||
final int baseId = Integer.MIN_VALUE;
|
||||
|
||||
queue.enqueueConfiguration(
|
||||
new SettingsChannel.ConfigurationQueue.SentConfiguration(mock(DisplayMetrics.class)));
|
||||
queue.enqueueConfiguration(
|
||||
new SettingsChannel.ConfigurationQueue.SentConfiguration(mock(DisplayMetrics.class)));
|
||||
assertEquals(baseId + 0, queue.getConfiguration(baseId + 0).generationNumber);
|
||||
assertEquals(baseId + 1, queue.getConfiguration(baseId + 1).generationNumber);
|
||||
assertEquals(baseId + 1, queue.getConfiguration(baseId + 1).generationNumber);
|
||||
|
||||
queue.enqueueConfiguration(
|
||||
new SettingsChannel.ConfigurationQueue.SentConfiguration(mock(DisplayMetrics.class)));
|
||||
queue.enqueueConfiguration(
|
||||
new SettingsChannel.ConfigurationQueue.SentConfiguration(mock(DisplayMetrics.class)));
|
||||
assertEquals(baseId + 3, queue.getConfiguration(baseId + 3).generationNumber);
|
||||
// Can get the same configuration more than once.
|
||||
assertEquals(baseId + 3, queue.getConfiguration(baseId + 3).generationNumber);
|
||||
|
||||
final BasicMessageChannel.Reply replyFor4 =
|
||||
queue.enqueueConfiguration(
|
||||
new SettingsChannel.ConfigurationQueue.SentConfiguration(mock(DisplayMetrics.class)));
|
||||
final BasicMessageChannel.Reply replyFor5 =
|
||||
queue.enqueueConfiguration(
|
||||
new SettingsChannel.ConfigurationQueue.SentConfiguration(mock(DisplayMetrics.class)));
|
||||
replyFor4.reply(null);
|
||||
replyFor5.reply(null);
|
||||
assertEquals(baseId + 5, queue.getConfiguration(baseId + 5).generationNumber);
|
||||
assertEquals(baseId + 5, queue.getConfiguration(baseId + 5).generationNumber);
|
||||
}
|
||||
}
|
||||
@@ -95,12 +95,4 @@ void main() {
|
||||
expect(flutterView.viewId, 0);
|
||||
expect(flutterView.toString(), 'FlutterView(id: 0)');
|
||||
});
|
||||
|
||||
test('scaleFontSize is the identity function by default when textScaleFactor = 1', () {
|
||||
expect(PlatformDispatcher.instance.scaleFontSize(0), 0.0);
|
||||
expect(PlatformDispatcher.instance.scaleFontSize(1), 1.0);
|
||||
expect(PlatformDispatcher.instance.scaleFontSize(2), 2.0);
|
||||
expect(PlatformDispatcher.instance.scaleFontSize(3), 3.0);
|
||||
expect(PlatformDispatcher.instance.scaleFontSize(3.4), 3.4);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user