diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 3d02635b70dc9..6cfa3cb2b17bc 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -44329,6 +44329,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/syst ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/ProcessTextChannel.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/RestorationChannel.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/ScribeChannel.java + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SensitiveContentChannel.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SystemChannel.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/common/ActivityLifecycleListener.java + ../../../flutter/LICENSE @@ -44353,6 +44354,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/ImeSyn ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/ListenableEditingState.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/ScribePlugin.java + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/view/SensitiveContentPlugin.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/SpellCheckPlugin.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextEditingDelta.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java + ../../../flutter/LICENSE diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 4b6ea453c09ed..d6fb9c4208dfd 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -286,6 +286,7 @@ android_java_sources = [ "io/flutter/embedding/engine/systemchannels/ProcessTextChannel.java", "io/flutter/embedding/engine/systemchannels/RestorationChannel.java", "io/flutter/embedding/engine/systemchannels/ScribeChannel.java", + "io/flutter/embedding/engine/systemchannels/SensitiveContentChannel.java", "io/flutter/embedding/engine/systemchannels/SettingsChannel.java", "io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java", "io/flutter/embedding/engine/systemchannels/SystemChannel.java", @@ -338,6 +339,7 @@ android_java_sources = [ "io/flutter/plugin/platform/VirtualDisplayController.java", "io/flutter/plugin/platform/WindowManagerHandler.java", "io/flutter/plugin/text/ProcessTextPlugin.java", + "io/flutter/plugin/view/SensitiveContentPlugin.java", "io/flutter/util/HandlerCompat.java", "io/flutter/util/PathUtils.java", "io/flutter/util/Preconditions.java", diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index f5794335b74f4..f406a3374a7cd 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -54,6 +54,7 @@ import io.flutter.embedding.engine.plugins.activity.ActivityControlSurface; import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister; import io.flutter.plugin.platform.PlatformPlugin; +import io.flutter.plugin.view.SensitiveContentPlugin; import java.util.ArrayList; import java.util.List; @@ -220,7 +221,7 @@ public class FlutterActivity extends Activity *
This ID can be used to lookup {@code FlutterView} in the Android view hierarchy. For more, * see {@link android.view.View#findViewById}. */ - public static final int FLUTTER_VIEW_ID = View.generateViewId(); + public static final int FLUTTER_VIEW_ID = 0; /** * Creates an {@link Intent} that launches a {@code FlutterActivity}, which creates a {@link @@ -1312,6 +1313,13 @@ public PlatformPlugin providePlatformPlugin( return new PlatformPlugin(getActivity(), flutterEngine.getPlatformChannel(), this); } + @Nullable + @Override + public SensitiveContentPlugin provideSensitiveContentPlugin( + @Nullable Activity activity, @NonNull FlutterEngine flutterEngine) { + return new SensitiveContentPlugin(getActivity(), flutterEngine.getSensitiveContentChannel()); + } + /** * Hook for subclasses to easily configure a {@code FlutterEngine}. * diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index c576eacda8c0c..5dec91176c540 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -36,6 +36,7 @@ import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener; import io.flutter.plugin.platform.PlatformPlugin; +import io.flutter.plugin.view.SensitiveContentPlugin; import java.util.Arrays; import java.util.List; @@ -89,6 +90,7 @@ public interface DelegateFactory { @Nullable private FlutterEngine flutterEngine; @VisibleForTesting @Nullable FlutterView flutterView; @Nullable private PlatformPlugin platformPlugin; + @Nullable private SensitiveContentPlugin sensitiveContentPlugin; @VisibleForTesting @Nullable OnPreDrawListener activePreDrawListener; private boolean isFlutterEngineFromHost; private boolean isFlutterUiDisplayed; @@ -140,6 +142,7 @@ void release() { this.flutterEngine = null; this.flutterView = null; this.platformPlugin = null; + this.sensitiveContentPlugin = null; } /** @@ -215,6 +218,7 @@ void onAttach(@NonNull Context context) { // control of the entire window. This is unacceptable for non-fullscreen // use-cases. platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine); + sensitiveContentPlugin = host.provideSensitiveContentPlugin(host.getActivity(), flutterEngine); host.configureFlutterEngine(flutterEngine); isAttached = true; @@ -756,6 +760,11 @@ void onDetach() { platformPlugin = null; } + if (sensitiveContentPlugin != null) { + sensitiveContentPlugin.destroy(); + sensitiveContentPlugin = null; + } + if (host.shouldDispatchAppLifecycleState() && flutterEngine != null) { flutterEngine.getLifecycleChannel().appIsDetached(); } @@ -1184,6 +1193,14 @@ private void ensureAlive() { PlatformPlugin providePlatformPlugin( @Nullable Activity activity, @NonNull FlutterEngine flutterEngine); + /** + * Hook for host to create/provide a {@link SensitiveContentPlugin} if the associated Flutter + * experience should set content sensitivity. + */ + @Nullable + SensitiveContentPlugin provideSensitiveContentPlugin( + @Nullable Activity activity, @NonNull FlutterEngine flutterEngine); + /** * Hook for the host to configure the {@link io.flutter.embedding.engine.FlutterEngine} as * desired. diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index e26d13e80f74a..5976ba22bd79b 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -25,6 +25,7 @@ import io.flutter.embedding.engine.FlutterShellArgs; import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener; import io.flutter.plugin.platform.PlatformPlugin; +import io.flutter.plugin.view.SensitiveContentPlugin; import java.util.ArrayList; import java.util.List; @@ -104,7 +105,8 @@ public class FlutterFragment extends Fragment *
This ID can be used to lookup {@code FlutterView} in the Android view hierarchy. For more, * see {@link android.view.View#findViewById}. */ - public static final int FLUTTER_VIEW_ID = View.generateViewId(); + // TODO(camsim99): Determine if we should involve FlutterFragment. + public static final int FLUTTER_VIEW_ID = 1; private static final String TAG = "FlutterFragment"; @@ -1501,6 +1503,17 @@ public PlatformPlugin providePlatformPlugin( } } + @Nullable + @Override + public SensitiveContentPlugin provideSensitiveContentPlugin( + @Nullable Activity activity, @NonNull FlutterEngine flutterEngine) { + if (activity != null) { + return new SensitiveContentPlugin(getActivity(), flutterEngine.getSensitiveContentChannel()); + } else { + return null; + } + } + /** * Configures a {@link io.flutter.embedding.engine.FlutterEngine} after its creation. * diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 683dfeace7937..43916b46c6a7b 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -35,6 +35,7 @@ import io.flutter.embedding.engine.systemchannels.ProcessTextChannel; import io.flutter.embedding.engine.systemchannels.RestorationChannel; import io.flutter.embedding.engine.systemchannels.ScribeChannel; +import io.flutter.embedding.engine.systemchannels.SensitiveContentChannel; import io.flutter.embedding.engine.systemchannels.SettingsChannel; import io.flutter.embedding.engine.systemchannels.SpellCheckChannel; import io.flutter.embedding.engine.systemchannels.SystemChannel; @@ -102,6 +103,7 @@ public class FlutterEngine implements ViewUtils.DisplayUpdater { @NonNull private final PlatformChannel platformChannel; @NonNull private final ProcessTextChannel processTextChannel; @NonNull private final ScribeChannel scribeChannel; + @NonNull private final SensitiveContentChannel sensitiveContentChannel; @NonNull private final SettingsChannel settingsChannel; @NonNull private final SpellCheckChannel spellCheckChannel; @NonNull private final SystemChannel systemChannel; @@ -340,6 +342,7 @@ public FlutterEngine( processTextChannel = new ProcessTextChannel(dartExecutor, context.getPackageManager()); restorationChannel = new RestorationChannel(dartExecutor, waitForRestorationData); scribeChannel = new ScribeChannel(dartExecutor); + sensitiveContentChannel = new SensitiveContentChannel(dartExecutor); settingsChannel = new SettingsChannel(dartExecutor); spellCheckChannel = new SpellCheckChannel(dartExecutor); systemChannel = new SystemChannel(dartExecutor); @@ -619,6 +622,12 @@ public ScribeChannel getScribeChannel() { return scribeChannel; } + /** System channel that handles setting content sensitivity. */ + @NonNull + public SensitiveContentChannel getSensitiveContentChannel() { + return sensitiveContentChannel; + } + /** System channel that sends and receives spell check requests and results. */ @NonNull public SpellCheckChannel getSpellCheckChannel() { diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/SensitiveContentChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/SensitiveContentChannel.java new file mode 100644 index 0000000000000..63a07adde3899 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/SensitiveContentChannel.java @@ -0,0 +1,84 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.embedding.engine.systemchannels; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import io.flutter.Log; +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.StandardMethodCodec; +import java.util.ArrayList; + +/** + * {@link SensitiveContentChannel} is a platform channel that is used by the framework to set the + * content sensitivity of native Flutter Android {@code View}s. + */ +public class SensitiveContentChannel { + private static final String TAG = "SensitiveContentChannel"; + + public final MethodChannel channel; + private SensitiveContentMethodHandler sensitiveContentMethodHandler; + + @NonNull + public final MethodChannel.MethodCallHandler parsingMethodHandler = + new MethodChannel.MethodCallHandler() { + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + if (sensitiveContentMethodHandler == null) { + Log.v( + TAG, + "No SensitiveContentChannel registered, call not forwarded to sensitive content API."); + return; + } + String method = call.method; + Object args = call.arguments; + Log.v(TAG, "Received '" + method + "' message."); + switch (method) { + case "SensitiveContent.setContentSensitivity": + final ArrayList