mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Delete v1 android engine embedding (flutter/engine#52022)
Fixes https://github.com/flutter/flutter/issues/143531 Other failures from the initial attempt are fixed in https://github.com/flutter/flutter/pull/146523/
This commit is contained in:
parent
3e89cd79b5
commit
c5d163fccb
@ -44211,13 +44211,6 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/Build.java + ../../..
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/BuildConfig.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/FlutterInjector.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/Log.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivity.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivityEvents.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/app/FlutterApplication.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/app/FlutterFragmentActivity.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/app/FlutterPlayStoreSplitApplication.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/ExclusiveAppComponent.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java + ../../../flutter/LICENSE
|
||||
@ -44274,8 +44267,6 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plug
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServiceAware.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServiceControlSurface.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServicePluginBinding.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimPluginRegistry.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/util/GeneratedPluginRegister.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterUiDisplayListener.java + ../../../flutter/LICENSE
|
||||
@ -44349,10 +44340,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/util/ViewUtils.java +
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/AccessibilityViewEmbedder.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterMain.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterNativeView.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArguments.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/android/jni/jni_mock.h + ../../../flutter/LICENSE
|
||||
@ -47088,13 +47076,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/Build.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/BuildConfig.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/FlutterInjector.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/Log.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivity.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivityEvents.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterApplication.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterFragmentActivity.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterPlayStoreSplitApplication.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/ExclusiveAppComponent.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java
|
||||
@ -47154,8 +47135,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugin
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServiceAware.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServiceControlSurface.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServicePluginBinding.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimPluginRegistry.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/util/GeneratedPluginRegister.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterUiDisplayListener.java
|
||||
@ -47237,10 +47216,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/util/ViewUtils.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/AccessibilityViewEmbedder.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterMain.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterNativeView.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArguments.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java
|
||||
FILE: ../../../flutter/shell/platform/android/jni/jni_mock.h
|
||||
|
||||
@ -3,28 +3,13 @@
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.flutter.app" android:versionCode="1" android:versionName="0.0.1">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.flutter.embedding" android:versionCode="1" android:versionName="0.0.1">
|
||||
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="35" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
|
||||
|
||||
<application android:label="Flutter Shell" android:name="FlutterApplication" android:debuggable="true">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="standard"
|
||||
android:name="FlutterActivity"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<!-- Required for io.flutter.plugin.text.ProcessTextPlugin to query activities that can process text. -->
|
||||
<queries>
|
||||
<intent>
|
||||
|
||||
@ -207,13 +207,6 @@ android_java_sources = [
|
||||
"io/flutter/Build.java",
|
||||
"io/flutter/FlutterInjector.java",
|
||||
"io/flutter/Log.java",
|
||||
"io/flutter/app/FlutterActivity.java",
|
||||
"io/flutter/app/FlutterActivityDelegate.java",
|
||||
"io/flutter/app/FlutterActivityEvents.java",
|
||||
"io/flutter/app/FlutterApplication.java",
|
||||
"io/flutter/app/FlutterFragmentActivity.java",
|
||||
"io/flutter/app/FlutterPlayStoreSplitApplication.java",
|
||||
"io/flutter/app/FlutterPluginRegistry.java",
|
||||
"io/flutter/embedding/android/AndroidTouchProcessor.java",
|
||||
"io/flutter/embedding/android/ExclusiveAppComponent.java",
|
||||
"io/flutter/embedding/android/FlutterActivity.java",
|
||||
@ -273,8 +266,6 @@ android_java_sources = [
|
||||
"io/flutter/embedding/engine/plugins/service/ServiceAware.java",
|
||||
"io/flutter/embedding/engine/plugins/service/ServiceControlSurface.java",
|
||||
"io/flutter/embedding/engine/plugins/service/ServicePluginBinding.java",
|
||||
"io/flutter/embedding/engine/plugins/shim/ShimPluginRegistry.java",
|
||||
"io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java",
|
||||
"io/flutter/embedding/engine/plugins/util/GeneratedPluginRegister.java",
|
||||
"io/flutter/embedding/engine/renderer/FlutterRenderer.java",
|
||||
"io/flutter/embedding/engine/renderer/FlutterUiDisplayListener.java",
|
||||
@ -356,10 +347,7 @@ android_java_sources = [
|
||||
"io/flutter/view/AccessibilityBridge.java",
|
||||
"io/flutter/view/AccessibilityViewEmbedder.java",
|
||||
"io/flutter/view/FlutterCallbackInformation.java",
|
||||
"io/flutter/view/FlutterMain.java",
|
||||
"io/flutter/view/FlutterNativeView.java",
|
||||
"io/flutter/view/FlutterRunArguments.java",
|
||||
"io/flutter/view/FlutterView.java",
|
||||
"io/flutter/view/TextureRegistry.java",
|
||||
"io/flutter/view/VsyncWaiter.java",
|
||||
]
|
||||
|
||||
@ -1,181 +0,0 @@
|
||||
// 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.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import io.flutter.app.FlutterActivityDelegate.ViewFactory;
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
import io.flutter.view.FlutterNativeView;
|
||||
import io.flutter.view.FlutterView;
|
||||
|
||||
/**
|
||||
* Deprecated base class for activities that use Flutter.
|
||||
*
|
||||
* @deprecated {@link io.flutter.embedding.android.FlutterActivity} is the new API that now replaces
|
||||
* this class. See https://flutter.dev/go/android-project-migration for more migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
public class FlutterActivity extends Activity
|
||||
implements FlutterView.Provider, PluginRegistry, ViewFactory {
|
||||
private static final String TAG = "FlutterActivity";
|
||||
|
||||
private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
|
||||
|
||||
// These aliases ensure that the methods we forward to the delegate adhere
|
||||
// to relevant interfaces versus just existing in FlutterActivityDelegate.
|
||||
private final FlutterActivityEvents eventDelegate = delegate;
|
||||
private final FlutterView.Provider viewProvider = delegate;
|
||||
private final PluginRegistry pluginRegistry = delegate;
|
||||
|
||||
/**
|
||||
* Returns the Flutter view used by this activity; will be null before {@link #onCreate(Bundle)}
|
||||
* is called.
|
||||
*/
|
||||
@Override
|
||||
public FlutterView getFlutterView() {
|
||||
return viewProvider.getFlutterView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for subclasses to customize the creation of the {@code FlutterView}.
|
||||
*
|
||||
* <p>The default implementation returns {@code null}, which will cause the activity to use a
|
||||
* newly instantiated full-screen view.
|
||||
*/
|
||||
@Override
|
||||
public FlutterView createFlutterView(Context context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for subclasses to customize the creation of the {@code FlutterNativeView}.
|
||||
*
|
||||
* <p>The default implementation returns {@code null}, which will cause the activity to use a
|
||||
* newly instantiated native view object.
|
||||
*/
|
||||
@Override
|
||||
public FlutterNativeView createFlutterNativeView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainFlutterNativeView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasPlugin(String key) {
|
||||
return pluginRegistry.hasPlugin(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T valuePublishedByPlugin(String pluginKey) {
|
||||
return pluginRegistry.valuePublishedByPlugin(pluginKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Registrar registrarFor(String pluginKey) {
|
||||
return pluginRegistry.registrarFor(pluginKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
eventDelegate.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
eventDelegate.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
eventDelegate.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
eventDelegate.onDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!eventDelegate.onBackPressed()) {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
eventDelegate.onStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
eventDelegate.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
eventDelegate.onPostResume();
|
||||
}
|
||||
|
||||
// @Override - added in API level 23
|
||||
public void onRequestPermissionsResult(
|
||||
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
eventDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (!eventDelegate.onActivityResult(requestCode, resultCode, data)) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
eventDelegate.onNewIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserLeaveHint() {
|
||||
eventDelegate.onUserLeaveHint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
eventDelegate.onWindowFocusChanged(hasFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
eventDelegate.onTrimMemory(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
eventDelegate.onLowMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
eventDelegate.onConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
||||
@ -1,495 +0,0 @@
|
||||
// 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.app;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import io.flutter.Log;
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
import io.flutter.plugin.platform.PlatformPlugin;
|
||||
import io.flutter.util.Preconditions;
|
||||
import io.flutter.view.FlutterMain;
|
||||
import io.flutter.view.FlutterNativeView;
|
||||
import io.flutter.view.FlutterRunArguments;
|
||||
import io.flutter.view.FlutterView;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Deprecated class that performs the actual work of tying Android {@link android.app.Activity}
|
||||
* instances to Flutter.
|
||||
*
|
||||
* <p>This exists as a dedicated class (as opposed to being integrated directly into {@link
|
||||
* FlutterActivity}) to facilitate applications that don't wish to subclass {@code FlutterActivity}.
|
||||
* The most obvious example of when this may come in handy is if an application wishes to subclass
|
||||
* the Android v4 support library's {@code FragmentActivity}.
|
||||
*
|
||||
* <p><b>Usage:</b>
|
||||
*
|
||||
* <p>To wire this class up to your activity, simply forward the events defined in {@link
|
||||
* FlutterActivityEvents} from your activity to an instance of this class. Optionally, you can make
|
||||
* your activity implement {@link PluginRegistry} and/or {@link
|
||||
* io.flutter.view.FlutterView.Provider} and forward those methods to this class as well.
|
||||
*
|
||||
* @deprecated {@link io.flutter.embedding.android.FlutterActivity} is the new API that now replaces
|
||||
* this class and {@link io.flutter.app.FlutterActivity}. See
|
||||
* https://flutter.dev/go/android-project-migration for more migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class FlutterActivityDelegate
|
||||
implements FlutterActivityEvents, FlutterView.Provider, PluginRegistry {
|
||||
private static final String SPLASH_SCREEN_META_DATA_KEY =
|
||||
"io.flutter.app.android.SplashScreenUntilFirstFrame";
|
||||
private static final String TAG = "FlutterActivityDelegate";
|
||||
private static final LayoutParams matchParent =
|
||||
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
|
||||
/**
|
||||
* Specifies the mechanism by which Flutter views are created during the operation of a {@code
|
||||
* FlutterActivityDelegate}.
|
||||
*
|
||||
* <p>A delegate's view factory will be consulted during {@link #onCreate(Bundle)}. If it returns
|
||||
* {@code null}, then the delegate will fall back to instantiating a new full-screen {@code
|
||||
* FlutterView}.
|
||||
*
|
||||
* <p>A delegate's native view factory will be consulted during {@link #onCreate(Bundle)}. If it
|
||||
* returns {@code null}, then the delegate will fall back to instantiating a new {@code
|
||||
* FlutterNativeView}. This is useful for applications to override to reuse the FlutterNativeView
|
||||
* held e.g. by a pre-existing background service.
|
||||
*/
|
||||
public interface ViewFactory {
|
||||
FlutterView createFlutterView(Context context);
|
||||
|
||||
FlutterNativeView createFlutterNativeView();
|
||||
|
||||
/**
|
||||
* Hook for subclasses to indicate that the {@code FlutterNativeView} returned by {@link
|
||||
* #createFlutterNativeView()} should not be destroyed when this activity is destroyed.
|
||||
*
|
||||
* @return Whether the FlutterNativeView is retained.
|
||||
*/
|
||||
boolean retainFlutterNativeView();
|
||||
}
|
||||
|
||||
private final Activity activity;
|
||||
private final ViewFactory viewFactory;
|
||||
private FlutterView flutterView;
|
||||
private View launchView;
|
||||
|
||||
public FlutterActivityDelegate(Activity activity, ViewFactory viewFactory) {
|
||||
this.activity = Preconditions.checkNotNull(activity);
|
||||
this.viewFactory = Preconditions.checkNotNull(viewFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlutterView getFlutterView() {
|
||||
return flutterView;
|
||||
}
|
||||
|
||||
// The implementation of PluginRegistry forwards to flutterView.
|
||||
@Override
|
||||
public boolean hasPlugin(String key) {
|
||||
return flutterView.getPluginRegistry().hasPlugin(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T valuePublishedByPlugin(String pluginKey) {
|
||||
return (T) flutterView.getPluginRegistry().valuePublishedByPlugin(pluginKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar registrarFor(String pluginKey) {
|
||||
return flutterView.getPluginRegistry().registrarFor(pluginKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRequestPermissionsResult(
|
||||
int requestCode, String[] permissions, int[] grantResults) {
|
||||
return flutterView
|
||||
.getPluginRegistry()
|
||||
.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
return flutterView.getPluginRegistry().onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Window window = activity.getWindow();
|
||||
window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.setStatusBarColor(0x40000000);
|
||||
window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
|
||||
|
||||
String[] args = getArgsFromIntent(activity.getIntent());
|
||||
FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);
|
||||
|
||||
flutterView = viewFactory.createFlutterView(activity);
|
||||
if (flutterView == null) {
|
||||
FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
|
||||
flutterView = new FlutterView(activity, null, nativeView);
|
||||
flutterView.setLayoutParams(matchParent);
|
||||
activity.setContentView(flutterView);
|
||||
launchView = createLaunchView();
|
||||
if (launchView != null) {
|
||||
addLaunchView();
|
||||
}
|
||||
}
|
||||
|
||||
if (loadIntent(activity.getIntent())) {
|
||||
return;
|
||||
}
|
||||
|
||||
String appBundlePath = FlutterMain.findAppBundlePath();
|
||||
if (appBundlePath != null) {
|
||||
runBundle(appBundlePath);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
// Only attempt to reload the Flutter Dart code during development. Use
|
||||
// the debuggable flag as an indicator that we are in development mode.
|
||||
if (!isDebuggable() || !loadIntent(intent)) {
|
||||
flutterView.getPluginRegistry().onNewIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDebuggable() {
|
||||
return (activity.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
Application app = (Application) activity.getApplicationContext();
|
||||
if (app instanceof FlutterApplication) {
|
||||
FlutterApplication flutterApp = (FlutterApplication) app;
|
||||
if (activity.equals(flutterApp.getCurrentActivity())) {
|
||||
flutterApp.setCurrentActivity(null);
|
||||
}
|
||||
}
|
||||
if (flutterView != null) {
|
||||
flutterView.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (flutterView != null) {
|
||||
flutterView.onStart();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
Application app = (Application) activity.getApplicationContext();
|
||||
if (app instanceof FlutterApplication) {
|
||||
FlutterApplication flutterApp = (FlutterApplication) app;
|
||||
flutterApp.setCurrentActivity(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
flutterView.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostResume() {
|
||||
if (flutterView != null) {
|
||||
flutterView.onPostResume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Application app = (Application) activity.getApplicationContext();
|
||||
if (app instanceof FlutterApplication) {
|
||||
FlutterApplication flutterApp = (FlutterApplication) app;
|
||||
if (activity.equals(flutterApp.getCurrentActivity())) {
|
||||
flutterApp.setCurrentActivity(null);
|
||||
}
|
||||
}
|
||||
if (flutterView != null) {
|
||||
final boolean detach =
|
||||
flutterView.getPluginRegistry().onViewDestroy(flutterView.getFlutterNativeView());
|
||||
if (detach || viewFactory.retainFlutterNativeView()) {
|
||||
// Detach, but do not destroy the FlutterView if a plugin
|
||||
// expressed interest in its FlutterNativeView.
|
||||
flutterView.detach();
|
||||
} else {
|
||||
flutterView.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
if (flutterView != null) {
|
||||
flutterView.popRoute();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserLeaveHint() {
|
||||
flutterView.getPluginRegistry().onUserLeaveHint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
flutterView.getPluginRegistry().onWindowFocusChanged(hasFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
// Use a trim level delivered while the application is running so the
|
||||
// framework has a chance to react to the notification.
|
||||
if (level == TRIM_MEMORY_RUNNING_LOW) {
|
||||
flutterView.onMemoryPressure();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
flutterView.onMemoryPressure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {}
|
||||
|
||||
private static String[] getArgsFromIntent(Intent intent) {
|
||||
// Before adding more entries to this list, consider that arbitrary
|
||||
// Android applications can generate intents with extra data and that
|
||||
// there are many security-sensitive args in the binary.
|
||||
ArrayList<String> args = new ArrayList<>();
|
||||
if (intent.getBooleanExtra("trace-startup", false)) {
|
||||
args.add("--trace-startup");
|
||||
}
|
||||
if (intent.getBooleanExtra("start-paused", false)) {
|
||||
args.add("--start-paused");
|
||||
}
|
||||
if (intent.getBooleanExtra("disable-service-auth-codes", false)) {
|
||||
args.add("--disable-service-auth-codes");
|
||||
}
|
||||
if (intent.getBooleanExtra("use-test-fonts", false)) {
|
||||
args.add("--use-test-fonts");
|
||||
}
|
||||
if (intent.getBooleanExtra("enable-dart-profiling", false)) {
|
||||
args.add("--enable-dart-profiling");
|
||||
}
|
||||
if (intent.getBooleanExtra("enable-software-rendering", false)) {
|
||||
args.add("--enable-software-rendering");
|
||||
}
|
||||
if (intent.getBooleanExtra("skia-deterministic-rendering", false)) {
|
||||
args.add("--skia-deterministic-rendering");
|
||||
}
|
||||
if (intent.getBooleanExtra("trace-skia", false)) {
|
||||
args.add("--trace-skia");
|
||||
}
|
||||
if (intent.getBooleanExtra("trace-systrace", false)) {
|
||||
args.add("--trace-systrace");
|
||||
}
|
||||
if (intent.hasExtra("trace-to-file")) {
|
||||
args.add("--trace-to-file=" + intent.getStringExtra("trace-to-file"));
|
||||
}
|
||||
if (intent.getBooleanExtra("dump-skp-on-shader-compilation", false)) {
|
||||
args.add("--dump-skp-on-shader-compilation");
|
||||
}
|
||||
if (intent.getBooleanExtra("cache-sksl", false)) {
|
||||
args.add("--cache-sksl");
|
||||
}
|
||||
if (intent.getBooleanExtra("purge-persistent-cache", false)) {
|
||||
args.add("--purge-persistent-cache");
|
||||
}
|
||||
if (intent.getBooleanExtra("verbose-logging", false)) {
|
||||
args.add("--verbose-logging");
|
||||
}
|
||||
int vmServicePort = intent.getIntExtra("vm-service-port", 0);
|
||||
if (vmServicePort > 0) {
|
||||
args.add("--vm-service-port=" + Integer.toString(vmServicePort));
|
||||
} else {
|
||||
// TODO(bkonyi): remove once flutter_tools no longer uses this option.
|
||||
// See https://github.com/dart-lang/sdk/issues/50233
|
||||
vmServicePort = intent.getIntExtra("observatory-port", 0);
|
||||
if (vmServicePort > 0) {
|
||||
args.add("--vm-service-port=" + Integer.toString(vmServicePort));
|
||||
}
|
||||
}
|
||||
if (intent.getBooleanExtra("endless-trace-buffer", false)) {
|
||||
args.add("--endless-trace-buffer");
|
||||
}
|
||||
// NOTE: all flags provided with this argument are subject to filtering
|
||||
// based on a list of allowed flags in shell/common/switches.cc. If any
|
||||
// flag provided is not allowed, the process will immediately terminate.
|
||||
if (intent.hasExtra("dart-flags")) {
|
||||
args.add("--dart-flags=" + intent.getStringExtra("dart-flags"));
|
||||
}
|
||||
if (!args.isEmpty()) {
|
||||
String[] argsArray = new String[args.size()];
|
||||
return args.toArray(argsArray);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean loadIntent(Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_RUN.equals(action)) {
|
||||
String route = intent.getStringExtra("route");
|
||||
String appBundlePath = intent.getDataString();
|
||||
if (appBundlePath == null) {
|
||||
// Fall back to the installation path if no bundle path was specified.
|
||||
appBundlePath = FlutterMain.findAppBundlePath();
|
||||
}
|
||||
if (route != null) {
|
||||
flutterView.setInitialRoute(route);
|
||||
}
|
||||
|
||||
runBundle(appBundlePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void runBundle(String appBundlePath) {
|
||||
if (!flutterView.getFlutterNativeView().isApplicationRunning()) {
|
||||
FlutterRunArguments args = new FlutterRunArguments();
|
||||
args.bundlePath = appBundlePath;
|
||||
args.entrypoint = "main";
|
||||
flutterView.runFromBundle(args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link View} containing the same {@link Drawable} as the one set as the {@code
|
||||
* windowBackground} of the parent activity for use as a launch splash view.
|
||||
*
|
||||
* <p>Returns null if no {@code windowBackground} is set for the activity.
|
||||
*/
|
||||
private View createLaunchView() {
|
||||
if (!showSplashScreenUntilFirstFrame()) {
|
||||
return null;
|
||||
}
|
||||
final Drawable launchScreenDrawable = getLaunchScreenDrawableFromActivityTheme();
|
||||
if (launchScreenDrawable == null) {
|
||||
return null;
|
||||
}
|
||||
final View view = new View(activity);
|
||||
view.setLayoutParams(matchParent);
|
||||
view.setBackground(launchScreenDrawable);
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a {@link Drawable} from the parent activity's {@code windowBackground}.
|
||||
*
|
||||
* <p>{@code android:windowBackground} is specifically reused instead of a other attributes
|
||||
* because the Android framework can display it fast enough when launching the app as opposed to
|
||||
* anything defined in the Activity subclass.
|
||||
*
|
||||
* <p>Returns null if no {@code windowBackground} is set for the activity.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private Drawable getLaunchScreenDrawableFromActivityTheme() {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
if (!activity.getTheme().resolveAttribute(android.R.attr.windowBackground, typedValue, true)) {
|
||||
return null;
|
||||
}
|
||||
if (typedValue.resourceId == 0) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return activity.getResources().getDrawable(typedValue.resourceId);
|
||||
} catch (NotFoundException e) {
|
||||
Log.e(TAG, "Referenced launch screen windowBackground resource does not exist");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the user specify whether the activity's {@code windowBackground} is a launch screen and
|
||||
* should be shown until the first frame via a <meta-data> tag in the activity.
|
||||
*/
|
||||
private Boolean showSplashScreenUntilFirstFrame() {
|
||||
try {
|
||||
ActivityInfo activityInfo =
|
||||
activity
|
||||
.getPackageManager()
|
||||
.getActivityInfo(activity.getComponentName(), PackageManager.GET_META_DATA);
|
||||
Bundle metadata = activityInfo.metaData;
|
||||
return metadata != null && metadata.getBoolean(SPLASH_SCREEN_META_DATA_KEY);
|
||||
} catch (NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show and then automatically animate out the launch view.
|
||||
*
|
||||
* <p>If a launch screen is defined in the user application's AndroidManifest.xml as the
|
||||
* activity's {@code windowBackground}, display it on top of the {@link FlutterView} and remove
|
||||
* the activity's {@code windowBackground}.
|
||||
*
|
||||
* <p>Fade it out and remove it when the {@link FlutterView} renders its first frame.
|
||||
*/
|
||||
private void addLaunchView() {
|
||||
if (launchView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
activity.addContentView(launchView, matchParent);
|
||||
flutterView.addFirstFrameListener(
|
||||
new FlutterView.FirstFrameListener() {
|
||||
@Override
|
||||
public void onFirstFrame() {
|
||||
FlutterActivityDelegate.this
|
||||
.launchView
|
||||
.animate()
|
||||
.alpha(0f)
|
||||
// Use Android's default animation duration.
|
||||
.setListener(
|
||||
new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// Views added to an Activity's addContentView is always added to its
|
||||
// root FrameLayout.
|
||||
((ViewGroup) FlutterActivityDelegate.this.launchView.getParent())
|
||||
.removeView(FlutterActivityDelegate.this.launchView);
|
||||
FlutterActivityDelegate.this.launchView = null;
|
||||
}
|
||||
});
|
||||
|
||||
FlutterActivityDelegate.this.flutterView.removeFirstFrameListener(this);
|
||||
}
|
||||
});
|
||||
|
||||
// Resets the activity theme from the one containing the launch screen in the window
|
||||
// background to a blank one since the launch screen is now in a view in front of the
|
||||
// FlutterView.
|
||||
//
|
||||
// We can make this configurable if users want it.
|
||||
activity.setTheme(android.R.style.Theme_Black_NoTitleBar);
|
||||
}
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
// 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.app;
|
||||
|
||||
import android.content.ComponentCallbacks2;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import io.flutter.plugin.common.PluginRegistry.ActivityResultListener;
|
||||
import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener;
|
||||
|
||||
/**
|
||||
* A collection of Android {@code Activity} methods that are relevant to the core operation of
|
||||
* Flutter applications.
|
||||
*
|
||||
* <p>Application authors that use an activity other than {@link FlutterActivity} should forward all
|
||||
* events herein from their activity to an instance of {@link FlutterActivityDelegate} in order to
|
||||
* wire the activity up to the Flutter framework. This forwarding is already provided in {@code
|
||||
* FlutterActivity}.
|
||||
*/
|
||||
public interface FlutterActivityEvents
|
||||
extends ComponentCallbacks2, ActivityResultListener, RequestPermissionsResultListener {
|
||||
/**
|
||||
* @param savedInstanceState If the activity is being re-initialized after previously being shut
|
||||
* down then this Bundle contains the data it most recently supplied in {@code
|
||||
* onSaveInstanceState(Bundle)}.
|
||||
* @see android.app.Activity#onCreate(android.os.Bundle)
|
||||
*/
|
||||
void onCreate(Bundle savedInstanceState);
|
||||
|
||||
/**
|
||||
* @param intent The new intent that was started for the activity.
|
||||
* @see android.app.Activity#onNewIntent(Intent)
|
||||
*/
|
||||
void onNewIntent(Intent intent);
|
||||
|
||||
/** @see android.app.Activity#onPause() */
|
||||
void onPause();
|
||||
|
||||
/** @see android.app.Activity#onStart() */
|
||||
void onStart();
|
||||
|
||||
/** @see android.app.Activity#onResume() */
|
||||
void onResume();
|
||||
|
||||
/** @see android.app.Activity#onPostResume() */
|
||||
void onPostResume();
|
||||
|
||||
/** @see android.app.Activity#onDestroy() */
|
||||
void onDestroy();
|
||||
|
||||
/** @see android.app.Activity#onStop() */
|
||||
void onStop();
|
||||
|
||||
/**
|
||||
* Invoked when the activity has detected the user's press of the back key.
|
||||
*
|
||||
* @return {@code true} if the listener handled the event; {@code false} to let the activity
|
||||
* continue with its default back button handling.
|
||||
* @see android.app.Activity#onBackPressed()
|
||||
*/
|
||||
boolean onBackPressed();
|
||||
|
||||
/** @see android.app.Activity#onUserLeaveHint() */
|
||||
void onUserLeaveHint();
|
||||
|
||||
/**
|
||||
* @param hasFocus True if the current activity window has focus.
|
||||
* @see android.app.Activity#onWindowFocusChanged(boolean)
|
||||
*/
|
||||
void onWindowFocusChanged(boolean hasFocus);
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
// 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.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import androidx.annotation.CallSuper;
|
||||
import io.flutter.FlutterInjector;
|
||||
|
||||
/**
|
||||
* Flutter implementation of {@link android.app.Application}, managing application-level global
|
||||
* initializations.
|
||||
*
|
||||
* <p>Using this {@link android.app.Application} is not required when using APIs in the package
|
||||
* {@code io.flutter.embedding.android} since they self-initialize on first use.
|
||||
*/
|
||||
public class FlutterApplication extends Application {
|
||||
@Override
|
||||
@CallSuper
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
FlutterInjector.instance().flutterLoader().startInitialization(this);
|
||||
}
|
||||
|
||||
private Activity mCurrentActivity = null;
|
||||
|
||||
public Activity getCurrentActivity() {
|
||||
return mCurrentActivity;
|
||||
}
|
||||
|
||||
public void setCurrentActivity(Activity mCurrentActivity) {
|
||||
this.mCurrentActivity = mCurrentActivity;
|
||||
}
|
||||
}
|
||||
@ -1,181 +0,0 @@
|
||||
// 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.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import io.flutter.app.FlutterActivityDelegate.ViewFactory;
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
import io.flutter.view.FlutterNativeView;
|
||||
import io.flutter.view.FlutterView;
|
||||
|
||||
/**
|
||||
* Deprecated class for activities that use Flutter who also require the use of the Android v4
|
||||
* Support library's {@link FragmentActivity}.
|
||||
*
|
||||
* <p>Applications that don't have this need will likely want to use {@link FlutterActivity}
|
||||
* instead.
|
||||
*
|
||||
* <p><strong>Important!</strong> Flutter does not bundle the necessary Android v4 Support library
|
||||
* classes for this class to work at runtime. It is the responsibility of the app developer using
|
||||
* this class to ensure that they link against the v4 support library .jar file when creating their
|
||||
* app to ensure that {@link FragmentActivity} is available at runtime.
|
||||
*
|
||||
* @see <a target="_new"
|
||||
* href="https://developer.android.com/training/testing/set-up-project">https://developer.android.com/training/testing/set-up-project</a>
|
||||
* @deprecated this class is replaced by {@link
|
||||
* io.flutter.embedding.android.FlutterFragmentActivity}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class FlutterFragmentActivity extends FragmentActivity
|
||||
implements FlutterView.Provider, PluginRegistry, ViewFactory {
|
||||
private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
|
||||
|
||||
// These aliases ensure that the methods we forward to the delegate adhere
|
||||
// to relevant interfaces versus just existing in FlutterActivityDelegate.
|
||||
private final FlutterActivityEvents eventDelegate = delegate;
|
||||
private final FlutterView.Provider viewProvider = delegate;
|
||||
private final PluginRegistry pluginRegistry = delegate;
|
||||
|
||||
/**
|
||||
* Returns the Flutter view used by this activity; will be null before {@link #onCreate(Bundle)}
|
||||
* is called.
|
||||
*/
|
||||
@Override
|
||||
public FlutterView getFlutterView() {
|
||||
return viewProvider.getFlutterView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for subclasses to customize the creation of the {@code FlutterView}.
|
||||
*
|
||||
* <p>The default implementation returns {@code null}, which will cause the activity to use a
|
||||
* newly instantiated full-screen view.
|
||||
*/
|
||||
@Override
|
||||
public FlutterView createFlutterView(Context context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlutterNativeView createFlutterNativeView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainFlutterNativeView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasPlugin(String key) {
|
||||
return pluginRegistry.hasPlugin(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T valuePublishedByPlugin(String pluginKey) {
|
||||
return pluginRegistry.valuePublishedByPlugin(pluginKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Registrar registrarFor(String pluginKey) {
|
||||
return pluginRegistry.registrarFor(pluginKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
eventDelegate.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
eventDelegate.onDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!eventDelegate.onBackPressed()) {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
eventDelegate.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
eventDelegate.onStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
eventDelegate.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
eventDelegate.onPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(
|
||||
int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
eventDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (!eventDelegate.onActivityResult(requestCode, resultCode, data)) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
eventDelegate.onNewIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("MissingSuperCall")
|
||||
public void onUserLeaveHint() {
|
||||
eventDelegate.onUserLeaveHint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
eventDelegate.onWindowFocusChanged(hasFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
super.onTrimMemory(level);
|
||||
eventDelegate.onTrimMemory(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
eventDelegate.onLowMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
eventDelegate.onConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
// 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.app;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import com.google.android.play.core.splitcompat.SplitCompatApplication;
|
||||
import io.flutter.FlutterInjector;
|
||||
import io.flutter.embedding.engine.deferredcomponents.PlayStoreDeferredComponentManager;
|
||||
|
||||
/**
|
||||
* Flutter's extension of {@link SplitCompatApplication} that injects a {@link
|
||||
* PlayStoreDeferredComponentManager} with {@link FlutterInjector} to enable Split AOT Flutter apps.
|
||||
*
|
||||
* <p>To use this class, either have your custom application class extend
|
||||
* FlutterPlayStoreSplitApplication or use it directly in the app's AndroidManifest.xml by adding
|
||||
* the following line:
|
||||
*
|
||||
* <pre>{@code
|
||||
* <manifest
|
||||
* ...
|
||||
* <application
|
||||
* android:name="io.flutter.app.FlutterPlayStoreSplitApplication"
|
||||
* ...>
|
||||
* </application>
|
||||
* </manifest>
|
||||
* }</pre>
|
||||
*
|
||||
* This class is meant to be used with the Google Play store. Custom non-play store applications do
|
||||
* not need to extend SplitCompatApplication and should inject a custom {@link
|
||||
* io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager} implementation like so:
|
||||
*
|
||||
* <pre>{@code
|
||||
* FlutterInjector.setInstance(
|
||||
* new FlutterInjector.Builder().setDeferredComponentManager(yourCustomManager).build());
|
||||
* }</pre>
|
||||
*/
|
||||
public class FlutterPlayStoreSplitApplication extends SplitCompatApplication {
|
||||
@Override
|
||||
@CallSuper
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// Create and inject a PlayStoreDeferredComponentManager, which is the default manager for
|
||||
// interacting with the Google Play Store.
|
||||
PlayStoreDeferredComponentManager deferredComponentManager =
|
||||
new PlayStoreDeferredComponentManager(this, null);
|
||||
FlutterInjector.setInstance(
|
||||
new FlutterInjector.Builder()
|
||||
.setDeferredComponentManager(deferredComponentManager)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@ -1,259 +0,0 @@
|
||||
// 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.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
import io.flutter.plugin.platform.PlatformViewRegistry;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
import io.flutter.view.FlutterMain;
|
||||
import io.flutter.view.FlutterNativeView;
|
||||
import io.flutter.view.FlutterView;
|
||||
import io.flutter.view.TextureRegistry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** @deprecated See https://flutter.dev/go/android-project-migration for migration instructions. */
|
||||
@Deprecated
|
||||
public class FlutterPluginRegistry
|
||||
implements PluginRegistry,
|
||||
PluginRegistry.RequestPermissionsResultListener,
|
||||
PluginRegistry.ActivityResultListener,
|
||||
PluginRegistry.NewIntentListener,
|
||||
PluginRegistry.WindowFocusChangedListener,
|
||||
PluginRegistry.UserLeaveHintListener,
|
||||
PluginRegistry.ViewDestroyListener {
|
||||
private static final String TAG = "FlutterPluginRegistry";
|
||||
|
||||
private Activity mActivity;
|
||||
private Context mAppContext;
|
||||
private FlutterNativeView mNativeView;
|
||||
private FlutterView mFlutterView;
|
||||
|
||||
private final PlatformViewsController mPlatformViewsController;
|
||||
private final Map<String, Object> mPluginMap = new LinkedHashMap<>(0);
|
||||
private final List<RequestPermissionsResultListener> mRequestPermissionsResultListeners =
|
||||
new ArrayList<>(0);
|
||||
private final List<ActivityResultListener> mActivityResultListeners = new ArrayList<>(0);
|
||||
private final List<NewIntentListener> mNewIntentListeners = new ArrayList<>(0);
|
||||
private final List<UserLeaveHintListener> mUserLeaveHintListeners = new ArrayList<>(0);
|
||||
private final List<WindowFocusChangedListener> mWindowFocusChangedListeners = new ArrayList<>(0);
|
||||
private final List<ViewDestroyListener> mViewDestroyListeners = new ArrayList<>(0);
|
||||
|
||||
public FlutterPluginRegistry(FlutterNativeView nativeView, Context context) {
|
||||
mNativeView = nativeView;
|
||||
mAppContext = context;
|
||||
mPlatformViewsController = new PlatformViewsController();
|
||||
}
|
||||
|
||||
public FlutterPluginRegistry(FlutterEngine engine, Context context) {
|
||||
// TODO(mattcarroll): implement use of engine instead of nativeView.
|
||||
mAppContext = context;
|
||||
mPlatformViewsController = new PlatformViewsController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPlugin(String key) {
|
||||
return mPluginMap.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T valuePublishedByPlugin(String pluginKey) {
|
||||
return (T) mPluginMap.get(pluginKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar registrarFor(String pluginKey) {
|
||||
if (mPluginMap.containsKey(pluginKey)) {
|
||||
throw new IllegalStateException("Plugin key " + pluginKey + " is already in use");
|
||||
}
|
||||
mPluginMap.put(pluginKey, null);
|
||||
return new FlutterRegistrar(pluginKey);
|
||||
}
|
||||
|
||||
public void attach(FlutterView flutterView, Activity activity) {
|
||||
mFlutterView = flutterView;
|
||||
mActivity = activity;
|
||||
mPlatformViewsController.attach(activity, flutterView, flutterView.getDartExecutor());
|
||||
}
|
||||
|
||||
public void detach() {
|
||||
mPlatformViewsController.detach();
|
||||
mPlatformViewsController.onDetachedFromJNI();
|
||||
mFlutterView = null;
|
||||
mActivity = null;
|
||||
}
|
||||
|
||||
public void onPreEngineRestart() {
|
||||
mPlatformViewsController.onPreEngineRestart();
|
||||
}
|
||||
|
||||
public PlatformViewsController getPlatformViewsController() {
|
||||
return mPlatformViewsController;
|
||||
}
|
||||
|
||||
private class FlutterRegistrar implements Registrar {
|
||||
private final String pluginKey;
|
||||
|
||||
FlutterRegistrar(String pluginKey) {
|
||||
this.pluginKey = pluginKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Activity activity() {
|
||||
return mActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context context() {
|
||||
return mAppContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context activeContext() {
|
||||
return (mActivity != null) ? mActivity : mAppContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryMessenger messenger() {
|
||||
return mNativeView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegistry textures() {
|
||||
return mFlutterView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformViewRegistry platformViewRegistry() {
|
||||
return mPlatformViewsController.getRegistry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlutterView view() {
|
||||
return mFlutterView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookupKeyForAsset(String asset) {
|
||||
return FlutterMain.getLookupKeyForAsset(asset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookupKeyForAsset(String asset, String packageName) {
|
||||
return FlutterMain.getLookupKeyForAsset(asset, packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar publish(Object value) {
|
||||
mPluginMap.put(pluginKey, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar addRequestPermissionsResultListener(
|
||||
RequestPermissionsResultListener listener) {
|
||||
mRequestPermissionsResultListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar addActivityResultListener(ActivityResultListener listener) {
|
||||
mActivityResultListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar addNewIntentListener(NewIntentListener listener) {
|
||||
mNewIntentListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar addUserLeaveHintListener(UserLeaveHintListener listener) {
|
||||
mUserLeaveHintListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar addWindowFocusChangedListener(WindowFocusChangedListener listener) {
|
||||
mWindowFocusChangedListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registrar addViewDestroyListener(ViewDestroyListener listener) {
|
||||
mViewDestroyListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRequestPermissionsResult(
|
||||
int requestCode, String[] permissions, int[] grantResults) {
|
||||
for (RequestPermissionsResultListener listener : mRequestPermissionsResultListeners) {
|
||||
if (listener.onRequestPermissionsResult(requestCode, permissions, grantResults)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
for (ActivityResultListener listener : mActivityResultListeners) {
|
||||
if (listener.onActivityResult(requestCode, resultCode, data)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNewIntent(Intent intent) {
|
||||
for (NewIntentListener listener : mNewIntentListeners) {
|
||||
if (listener.onNewIntent(intent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserLeaveHint() {
|
||||
for (UserLeaveHintListener listener : mUserLeaveHintListeners) {
|
||||
listener.onUserLeaveHint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
for (WindowFocusChangedListener listener : mWindowFocusChangedListeners) {
|
||||
listener.onWindowFocusChanged(hasFocus);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onViewDestroy(FlutterNativeView view) {
|
||||
boolean handled = false;
|
||||
for (ViewDestroyListener listener : mViewDestroyListeners) {
|
||||
if (listener.onViewDestroy(view)) {
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mPlatformViewsController.onDetachedFromJNI();
|
||||
}
|
||||
}
|
||||
@ -1039,8 +1039,7 @@ public class FlutterJNI {
|
||||
* will be dropped (ignored). Therefore, when using {@code FlutterJNI} to integrate a Flutter
|
||||
* context in an app, a {@link PlatformMessageHandler} must be registered for 2-way Java/Dart
|
||||
* communication to operate correctly. Moreover, the handler must be implemented such that
|
||||
* fundamental platform messages are handled as expected. See {@link
|
||||
* io.flutter.view.FlutterNativeView} for an example implementation.
|
||||
* fundamental platform messages are handled as expected.
|
||||
*/
|
||||
@UiThread
|
||||
public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler) {
|
||||
|
||||
@ -1,153 +0,0 @@
|
||||
// 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.plugins.shim;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A {@link PluginRegistry} that is shimmed to let old plugins use the new Android embedding and
|
||||
* plugin API behind the scenes.
|
||||
*
|
||||
* <p>The following is an example usage of {@code ShimPluginRegistry} within a {@code
|
||||
* FlutterActivity}:
|
||||
*
|
||||
* <pre>
|
||||
* // Create the FlutterEngine that will back the Flutter UI.
|
||||
* FlutterEngineGroup group = new FlutterEngineGroup(context);
|
||||
* FlutterEngine flutterEngine = group.createAndRunDefaultEngine(context);
|
||||
*
|
||||
* // Create a ShimPluginRegistry and wrap the FlutterEngine with the shim.
|
||||
* ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine, platformViewsController);
|
||||
*
|
||||
* // Use the GeneratedPluginRegistrant to add every plugin that's in the pubspec.
|
||||
* GeneratedPluginRegistrant.registerWith(shimPluginRegistry);
|
||||
* </pre>
|
||||
*/
|
||||
public class ShimPluginRegistry implements PluginRegistry {
|
||||
private static final String TAG = "ShimPluginRegistry";
|
||||
|
||||
private final FlutterEngine flutterEngine;
|
||||
private final Map<String, Object> pluginMap = new HashMap<>();
|
||||
private final ShimRegistrarAggregate shimRegistrarAggregate;
|
||||
|
||||
public ShimPluginRegistry(@NonNull FlutterEngine flutterEngine) {
|
||||
this.flutterEngine = flutterEngine;
|
||||
this.shimRegistrarAggregate = new ShimRegistrarAggregate();
|
||||
this.flutterEngine.getPlugins().add(shimRegistrarAggregate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Registrar registrarFor(@NonNull String pluginKey) {
|
||||
Log.v(TAG, "Creating plugin Registrar for '" + pluginKey + "'");
|
||||
if (pluginMap.containsKey(pluginKey)) {
|
||||
throw new IllegalStateException("Plugin key " + pluginKey + " is already in use");
|
||||
}
|
||||
pluginMap.put(pluginKey, null);
|
||||
ShimRegistrar registrar = new ShimRegistrar(pluginKey, pluginMap);
|
||||
shimRegistrarAggregate.addPlugin(registrar);
|
||||
return registrar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPlugin(@NonNull String pluginKey) {
|
||||
return pluginMap.containsKey(pluginKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T valuePublishedByPlugin(@NonNull String pluginKey) {
|
||||
return (T) pluginMap.get(pluginKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates all {@link ShimRegistrar}s within one single {@link FlutterPlugin}.
|
||||
*
|
||||
* <p>The reason we need this aggregate is because the new embedding uniquely identifies plugins
|
||||
* by their plugin class, but the plugin shim system represents every plugin with a {@link
|
||||
* ShimRegistrar}. Therefore, every plugin we would register after the first plugin, would
|
||||
* overwrite the previous plugin, because they're all {@link ShimRegistrar} instances.
|
||||
*
|
||||
* <p>{@code ShimRegistrarAggregate} multiplexes {@link FlutterPlugin} and {@link ActivityAware}
|
||||
* calls so that we can register just one {@code ShimRegistrarAggregate} with a {@link
|
||||
* FlutterEngine}, while forwarding the relevant plugin resources to any number of {@link
|
||||
* ShimRegistrar}s within this {@code ShimRegistrarAggregate}.
|
||||
*/
|
||||
private static class ShimRegistrarAggregate implements FlutterPlugin, ActivityAware {
|
||||
private final Set<ShimRegistrar> shimRegistrars = new HashSet<>();
|
||||
private FlutterPluginBinding flutterPluginBinding;
|
||||
private ActivityPluginBinding activityPluginBinding;
|
||||
|
||||
public void addPlugin(@NonNull ShimRegistrar shimRegistrar) {
|
||||
shimRegistrars.add(shimRegistrar);
|
||||
|
||||
if (flutterPluginBinding != null) {
|
||||
shimRegistrar.onAttachedToEngine(flutterPluginBinding);
|
||||
}
|
||||
if (activityPluginBinding != null) {
|
||||
shimRegistrar.onAttachedToActivity(activityPluginBinding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
|
||||
flutterPluginBinding = binding;
|
||||
for (ShimRegistrar shimRegistrar : shimRegistrars) {
|
||||
shimRegistrar.onAttachedToEngine(binding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
|
||||
for (ShimRegistrar shimRegistrar : shimRegistrars) {
|
||||
shimRegistrar.onDetachedFromEngine(binding);
|
||||
}
|
||||
flutterPluginBinding = null;
|
||||
activityPluginBinding = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
|
||||
activityPluginBinding = binding;
|
||||
for (ShimRegistrar shimRegistrar : shimRegistrars) {
|
||||
shimRegistrar.onAttachedToActivity(binding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromActivityForConfigChanges() {
|
||||
for (ShimRegistrar shimRegistrar : shimRegistrars) {
|
||||
shimRegistrar.onDetachedFromActivity();
|
||||
}
|
||||
activityPluginBinding = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
|
||||
activityPluginBinding = binding;
|
||||
for (ShimRegistrar shimRegistrar : shimRegistrars) {
|
||||
shimRegistrar.onReattachedToActivityForConfigChanges(binding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromActivity() {
|
||||
for (ShimRegistrar shimRegistrar : shimRegistrars) {
|
||||
shimRegistrar.onDetachedFromActivity();
|
||||
}
|
||||
activityPluginBinding = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,234 +0,0 @@
|
||||
// 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.plugins.shim;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import io.flutter.FlutterInjector;
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
import io.flutter.plugin.platform.PlatformViewRegistry;
|
||||
import io.flutter.view.FlutterView;
|
||||
import io.flutter.view.TextureRegistry;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A {@link PluginRegistry.Registrar} that is shimmed let old plugins use the new Android embedding
|
||||
* and plugin API behind the scenes.
|
||||
*
|
||||
* <p>Instances of {@code ShimRegistrar}s are vended internally by a {@link ShimPluginRegistry}.
|
||||
*/
|
||||
class ShimRegistrar implements PluginRegistry.Registrar, FlutterPlugin, ActivityAware {
|
||||
private static final String TAG = "ShimRegistrar";
|
||||
|
||||
private final Map<String, Object> globalRegistrarMap;
|
||||
private final String pluginId;
|
||||
private final Set<PluginRegistry.ViewDestroyListener> viewDestroyListeners = new HashSet<>();
|
||||
private final Set<PluginRegistry.RequestPermissionsResultListener>
|
||||
requestPermissionsResultListeners = new HashSet<>();
|
||||
private final Set<PluginRegistry.ActivityResultListener> activityResultListeners =
|
||||
new HashSet<>();
|
||||
private final Set<PluginRegistry.NewIntentListener> newIntentListeners = new HashSet<>();
|
||||
private final Set<PluginRegistry.UserLeaveHintListener> userLeaveHintListeners = new HashSet<>();
|
||||
private final Set<PluginRegistry.WindowFocusChangedListener> WindowFocusChangedListeners =
|
||||
new HashSet<>();
|
||||
private FlutterPlugin.FlutterPluginBinding pluginBinding;
|
||||
private ActivityPluginBinding activityPluginBinding;
|
||||
|
||||
public ShimRegistrar(@NonNull String pluginId, @NonNull Map<String, Object> globalRegistrarMap) {
|
||||
this.pluginId = pluginId;
|
||||
this.globalRegistrarMap = globalRegistrarMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Activity activity() {
|
||||
return activityPluginBinding != null ? activityPluginBinding.getActivity() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context context() {
|
||||
return pluginBinding != null ? pluginBinding.getApplicationContext() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context activeContext() {
|
||||
return activityPluginBinding == null ? context() : activity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryMessenger messenger() {
|
||||
return pluginBinding != null ? pluginBinding.getBinaryMessenger() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegistry textures() {
|
||||
return pluginBinding != null ? pluginBinding.getTextureRegistry() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformViewRegistry platformViewRegistry() {
|
||||
return pluginBinding != null ? pluginBinding.getPlatformViewRegistry() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlutterView view() {
|
||||
throw new UnsupportedOperationException(
|
||||
"The new embedding does not support the old FlutterView.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookupKeyForAsset(String asset) {
|
||||
return FlutterInjector.instance().flutterLoader().getLookupKeyForAsset(asset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookupKeyForAsset(String asset, String packageName) {
|
||||
return FlutterInjector.instance().flutterLoader().getLookupKeyForAsset(asset, packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginRegistry.Registrar publish(Object value) {
|
||||
globalRegistrarMap.put(pluginId, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginRegistry.Registrar addRequestPermissionsResultListener(
|
||||
PluginRegistry.RequestPermissionsResultListener listener) {
|
||||
requestPermissionsResultListeners.add(listener);
|
||||
|
||||
if (activityPluginBinding != null) {
|
||||
activityPluginBinding.addRequestPermissionsResultListener(listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginRegistry.Registrar addActivityResultListener(
|
||||
PluginRegistry.ActivityResultListener listener) {
|
||||
activityResultListeners.add(listener);
|
||||
|
||||
if (activityPluginBinding != null) {
|
||||
activityPluginBinding.addActivityResultListener(listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginRegistry.Registrar addNewIntentListener(PluginRegistry.NewIntentListener listener) {
|
||||
newIntentListeners.add(listener);
|
||||
|
||||
if (activityPluginBinding != null) {
|
||||
activityPluginBinding.addOnNewIntentListener(listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginRegistry.Registrar addUserLeaveHintListener(
|
||||
PluginRegistry.UserLeaveHintListener listener) {
|
||||
userLeaveHintListeners.add(listener);
|
||||
|
||||
if (activityPluginBinding != null) {
|
||||
activityPluginBinding.addOnUserLeaveHintListener(listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginRegistry.Registrar addWindowFocusChangedListener(
|
||||
PluginRegistry.WindowFocusChangedListener listener) {
|
||||
WindowFocusChangedListeners.add(listener);
|
||||
|
||||
if (activityPluginBinding != null) {
|
||||
activityPluginBinding.addOnWindowFocusChangedListener(listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public PluginRegistry.Registrar addViewDestroyListener(
|
||||
@NonNull PluginRegistry.ViewDestroyListener listener) {
|
||||
viewDestroyListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
|
||||
Log.v(TAG, "Attached to FlutterEngine.");
|
||||
pluginBinding = binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
|
||||
Log.v(TAG, "Detached from FlutterEngine.");
|
||||
for (PluginRegistry.ViewDestroyListener listener : viewDestroyListeners) {
|
||||
// The following invocation might produce unexpected behavior in old plugins because
|
||||
// we have no FlutterNativeView to pass to onViewDestroy(). This is a limitation of this shim.
|
||||
listener.onViewDestroy(null);
|
||||
}
|
||||
|
||||
pluginBinding = null;
|
||||
activityPluginBinding = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
|
||||
Log.v(TAG, "Attached to an Activity.");
|
||||
activityPluginBinding = binding;
|
||||
addExistingListenersToActivityPluginBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromActivityForConfigChanges() {
|
||||
Log.v(TAG, "Detached from an Activity for config changes.");
|
||||
activityPluginBinding = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
|
||||
Log.v(TAG, "Reconnected to an Activity after config changes.");
|
||||
activityPluginBinding = binding;
|
||||
addExistingListenersToActivityPluginBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromActivity() {
|
||||
Log.v(TAG, "Detached from an Activity.");
|
||||
activityPluginBinding = null;
|
||||
}
|
||||
|
||||
private void addExistingListenersToActivityPluginBinding() {
|
||||
for (PluginRegistry.RequestPermissionsResultListener listener :
|
||||
requestPermissionsResultListeners) {
|
||||
activityPluginBinding.addRequestPermissionsResultListener(listener);
|
||||
}
|
||||
for (PluginRegistry.ActivityResultListener listener : activityResultListeners) {
|
||||
activityPluginBinding.addActivityResultListener(listener);
|
||||
}
|
||||
for (PluginRegistry.NewIntentListener listener : newIntentListeners) {
|
||||
activityPluginBinding.addOnNewIntentListener(listener);
|
||||
}
|
||||
for (PluginRegistry.UserLeaveHintListener listener : userLeaveHintListeners) {
|
||||
activityPluginBinding.addOnUserLeaveHintListener(listener);
|
||||
}
|
||||
for (PluginRegistry.WindowFocusChangedListener listener : WindowFocusChangedListeners) {
|
||||
activityPluginBinding.addOnWindowFocusChangedListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,353 +5,13 @@
|
||||
package io.flutter.plugin.common;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
||||
import io.flutter.plugin.platform.PlatformViewRegistry;
|
||||
import io.flutter.view.FlutterNativeView;
|
||||
import io.flutter.view.FlutterView;
|
||||
import io.flutter.view.TextureRegistry;
|
||||
|
||||
/**
|
||||
* Container class for Android API listeners used by {@link ActivityPluginBinding}.
|
||||
*
|
||||
* <p>This class also contains deprecated v1 embedding APIs used for plugin registration.
|
||||
*
|
||||
* <p>In v1 Android applications, an auto-generated and auto-updated plugin registrant class
|
||||
* (GeneratedPluginRegistrant) makes use of a {@link PluginRegistry} to register contributions from
|
||||
* each plugin mentioned in the application's pubspec file. The generated registrant class is, again
|
||||
* by default, called from the application's main {@link android.app.Activity}, which defaults to an
|
||||
* instance of {@link io.flutter.app.FlutterActivity}, itself a {@link PluginRegistry}.
|
||||
*/
|
||||
/** Container class for Android API listeners used by {@link ActivityPluginBinding}. */
|
||||
public interface PluginRegistry {
|
||||
/**
|
||||
* Returns a {@link Registrar} for receiving the registrations pertaining to the specified plugin.
|
||||
*
|
||||
* @param pluginKey a unique String identifying the plugin; typically the fully qualified name of
|
||||
* the plugin's main class.
|
||||
* @return A {@link Registrar} for receiving the registrations pertianing to the specified plugin.
|
||||
* @deprecated See https://flutter.dev/go/android-project-migration for migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull
|
||||
Registrar registrarFor(@NonNull String pluginKey);
|
||||
|
||||
/**
|
||||
* Returns whether the specified plugin is known to this registry.
|
||||
*
|
||||
* @param pluginKey a unique String identifying the plugin; typically the fully qualified name of
|
||||
* the plugin's main class.
|
||||
* @return true if this registry has handed out a registrar for the specified plugin.
|
||||
* @deprecated See https://flutter.dev/go/android-project-migration for migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasPlugin(@NonNull String pluginKey);
|
||||
|
||||
/**
|
||||
* Returns the value published by the specified plugin, if any.
|
||||
*
|
||||
* <p>Plugins may publish a single value, such as an instance of the plugin's main class, for
|
||||
* situations where external control or interaction is needed. Clients are expected to know the
|
||||
* value's type.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
* @param pluginKey a unique String identifying the plugin; typically the fully qualified name of
|
||||
* the plugin's main class.
|
||||
* @return the published value, possibly null.
|
||||
* @deprecated See https://flutter.dev/go/android-project-migration for migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
@Nullable
|
||||
<T> T valuePublishedByPlugin(@NonNull String pluginKey);
|
||||
|
||||
/**
|
||||
* Receiver of registrations from a single plugin.
|
||||
*
|
||||
* @deprecated This registrar is for Flutter's v1 embedding. For instructions on migrating a
|
||||
* plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*/
|
||||
@Deprecated
|
||||
interface Registrar {
|
||||
/**
|
||||
* Returns the {@link android.app.Activity} that forms the plugin's operating context.
|
||||
*
|
||||
* <p>Plugin authors should not assume the type returned by this method is any specific subclass
|
||||
* of {@code Activity} (such as {@link io.flutter.app.FlutterActivity} or {@link
|
||||
* io.flutter.app.FlutterFragmentActivity}), as applications are free to use any activity
|
||||
* subclass.
|
||||
*
|
||||
* <p>When there is no foreground activity in the application, this will return null. If a
|
||||
* {@link Context} is needed, use context() to get the application's context.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To access an {@code Activity} from a plugin
|
||||
* using the v2 embedding, see {@link ActivityPluginBinding#getActivity()}. To obtain an
|
||||
* instance of an {@link ActivityPluginBinding} in a Flutter plugin, implement the {@link
|
||||
* ActivityAware} interface. A binding is provided in {@link
|
||||
* ActivityAware#onAttachedToActivity(ActivityPluginBinding)} and {@link
|
||||
* ActivityAware#onReattachedToActivityForConfigChanges(ActivityPluginBinding)}.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*/
|
||||
@Nullable
|
||||
Activity activity();
|
||||
|
||||
/**
|
||||
* Returns the {@link android.app.Application}'s {@link Context}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To access a {@code Context} from a plugin
|
||||
* using the v2 embedding, see {@link
|
||||
* FlutterPlugin.FlutterPluginBinding#getApplicationContext()}
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*/
|
||||
@NonNull
|
||||
Context context();
|
||||
|
||||
/**
|
||||
* Returns the active {@link Context}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. In the v2 embedding, there is no concept of
|
||||
* an "active context". Either use the application {@code Context} or an attached {@code
|
||||
* Activity}. See {@link #context()} and {@link #activity()} for more details.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*
|
||||
* @return the current {@link #activity() Activity}, if not null, otherwise the {@link
|
||||
* #context() Application}.
|
||||
*/
|
||||
@NonNull
|
||||
Context activeContext();
|
||||
|
||||
/**
|
||||
* Returns a {@link BinaryMessenger} which the plugin can use for creating channels for
|
||||
* communicating with the Dart side.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To access a {@code BinaryMessenger} from a
|
||||
* plugin using the v2 embedding, see {@link
|
||||
* FlutterPlugin.FlutterPluginBinding#getBinaryMessenger()}
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*/
|
||||
@NonNull
|
||||
BinaryMessenger messenger();
|
||||
|
||||
/**
|
||||
* Returns a {@link TextureRegistry} which the plugin can use for managing backend textures.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To access a {@code TextureRegistry} from a
|
||||
* plugin using the v2 embedding, see {@link
|
||||
* FlutterPlugin.FlutterPluginBinding#getTextureRegistry()}
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*/
|
||||
@NonNull
|
||||
TextureRegistry textures();
|
||||
|
||||
/**
|
||||
* Returns the application's {@link PlatformViewRegistry}.
|
||||
*
|
||||
* <p>Plugins can use the platform registry to register their view factories.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To access a {@code PlatformViewRegistry}
|
||||
* from a plugin using the v2 embedding, see {@link
|
||||
* FlutterPlugin.FlutterPluginBinding#getPlatformViewRegistry()}
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*/
|
||||
@NonNull
|
||||
PlatformViewRegistry platformViewRegistry();
|
||||
|
||||
/**
|
||||
* Returns the {@link FlutterView} that's instantiated by this plugin's {@link #activity()
|
||||
* activity}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. The {@link FlutterView} referenced by this
|
||||
* method does not exist in the v2 embedding. Additionally, no {@code View} is exposed to any
|
||||
* plugins in the v2 embedding. Platform views can access their containing {@code View} using
|
||||
* the platform views APIs. If you have a use-case that absolutely requires a plugin to access
|
||||
* an Android {@code View}, please file a ticket on GitHub.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*/
|
||||
@NonNull
|
||||
FlutterView view();
|
||||
|
||||
/**
|
||||
* Returns the file name for the given asset. The returned file name can be used to access the
|
||||
* asset in the APK through the {@link android.content.res.AssetManager} API.
|
||||
*
|
||||
* <p>TODO(mattcarroll): point this method towards new lookup method.
|
||||
*
|
||||
* @param asset the name of the asset. The name can be hierarchical
|
||||
* @return the filename to be used with {@link android.content.res.AssetManager}
|
||||
*/
|
||||
@NonNull
|
||||
String lookupKeyForAsset(@NonNull String asset);
|
||||
|
||||
/**
|
||||
* Returns the file name for the given asset which originates from the specified packageName.
|
||||
* The returned file name can be used to access the asset in the APK through the {@link
|
||||
* android.content.res.AssetManager} API.
|
||||
*
|
||||
* <p>TODO(mattcarroll): point this method towards new lookup method.
|
||||
*
|
||||
* @param asset the name of the asset. The name can be hierarchical
|
||||
* @param packageName the name of the package from which the asset originates
|
||||
* @return the file name to be used with {@link android.content.res.AssetManager}
|
||||
*/
|
||||
@NonNull
|
||||
String lookupKeyForAsset(@NonNull String asset, @NonNull String packageName);
|
||||
|
||||
/**
|
||||
* Publishes a value associated with the plugin being registered.
|
||||
*
|
||||
* <p>The published value is available to interested clients via {@link
|
||||
* PluginRegistry#valuePublishedByPlugin(String)}.
|
||||
*
|
||||
* <p>Publication should be done only when client code needs to interact with the plugin in a
|
||||
* way that cannot be accomplished by the plugin registering callbacks with client APIs.
|
||||
*
|
||||
* <p>Overwrites any previously published value.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. The concept of publishing values from
|
||||
* plugins is not supported in the v2 embedding.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*
|
||||
* @param value the value, possibly null.
|
||||
* @return this {@link Registrar}.
|
||||
*/
|
||||
@NonNull
|
||||
Registrar publish(@Nullable Object value);
|
||||
|
||||
/**
|
||||
* Adds a callback allowing the plugin to take part in handling incoming calls to {@code
|
||||
* Activity#onRequestPermissionsResult(int, String[], int[])} or {@code
|
||||
* androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(int,
|
||||
* String[], int[])}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To listen for permission results in the v2
|
||||
* embedding, use {@link
|
||||
* ActivityPluginBinding#addRequestPermissionsResultListener(PluginRegistry.RequestPermissionsResultListener)}.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*
|
||||
* @param listener a {@link RequestPermissionsResultListener} callback.
|
||||
* @return this {@link Registrar}.
|
||||
*/
|
||||
@NonNull
|
||||
Registrar addRequestPermissionsResultListener(
|
||||
@NonNull RequestPermissionsResultListener listener);
|
||||
|
||||
/**
|
||||
* Adds a callback allowing the plugin to take part in handling incoming calls to {@link
|
||||
* Activity#onActivityResult(int, int, Intent)}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To listen for {@code Activity} results in
|
||||
* the v2 embedding, use {@link
|
||||
* ActivityPluginBinding#addActivityResultListener(PluginRegistry.ActivityResultListener)}.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*
|
||||
* @param listener an {@link ActivityResultListener} callback.
|
||||
* @return this {@link Registrar}.
|
||||
*/
|
||||
@NonNull
|
||||
Registrar addActivityResultListener(@NonNull ActivityResultListener listener);
|
||||
|
||||
/**
|
||||
* Adds a callback allowing the plugin to take part in handling incoming calls to {@link
|
||||
* Activity#onNewIntent(Intent)}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To listen for new {@code Intent}s in the v2
|
||||
* embedding, use {@link
|
||||
* ActivityPluginBinding#addOnNewIntentListener(PluginRegistry.NewIntentListener)}.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*
|
||||
* @param listener a {@link NewIntentListener} callback.
|
||||
* @return this {@link Registrar}.
|
||||
*/
|
||||
@NonNull
|
||||
Registrar addNewIntentListener(@NonNull NewIntentListener listener);
|
||||
|
||||
/**
|
||||
* Adds a callback allowing the plugin to take part in handling incoming calls to {@link
|
||||
* Activity#onUserLeaveHint()}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To listen for leave hints in the v2
|
||||
* embedding, use {@link
|
||||
* ActivityPluginBinding#addOnUserLeaveHintListener(PluginRegistry.UserLeaveHintListener)}.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*
|
||||
* @param listener a {@link UserLeaveHintListener} callback.
|
||||
* @return this {@link Registrar}.
|
||||
*/
|
||||
@NonNull
|
||||
Registrar addUserLeaveHintListener(@NonNull UserLeaveHintListener listener);
|
||||
|
||||
/**
|
||||
* Adds a callback allowing the plugin to take part in handling incoming calls to {@link
|
||||
* Activity#onWindowFocusChanged(boolean)}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. To listen for leave hints in the v2
|
||||
* embedding, use {@link
|
||||
* ActivityPluginBinding#addOnWindowFocusChangedListener(PluginRegistry.WindowFocusChangedListener)}.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*
|
||||
* @param listener a {@link WindowFocusChangedListener} callback.
|
||||
* @return this {@link Registrar}.
|
||||
*/
|
||||
@NonNull
|
||||
Registrar addWindowFocusChangedListener(@NonNull WindowFocusChangedListener listener);
|
||||
|
||||
/**
|
||||
* Adds a callback allowing the plugin to take part in handling incoming calls to {@link
|
||||
* Activity#onDestroy()}.
|
||||
*
|
||||
* <p>This registrar is for Flutter's v1 embedding. The concept of {@code View} destruction does
|
||||
* not exist in the v2 embedding. However, plugins in the v2 embedding can respond to {@link
|
||||
* ActivityAware#onDetachedFromActivityForConfigChanges()} and {@link
|
||||
* ActivityAware#onDetachedFromActivity()}, which indicate the loss of a visual context for the
|
||||
* running Flutter experience. Developers should implement {@link ActivityAware} for their
|
||||
* {@link FlutterPlugin} if such callbacks are needed. Also, plugins can respond to {@link
|
||||
* FlutterPlugin#onDetachedFromEngine(FlutterPlugin.FlutterPluginBinding)}, which indicates that
|
||||
* the given plugin has been completely disconnected from the associated Flutter experience and
|
||||
* should clean up any resources.
|
||||
*
|
||||
* <p>For instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
|
||||
* http://flutter.dev/go/android-plugin-migration
|
||||
*
|
||||
* @param listener a {@link ViewDestroyListener} callback.
|
||||
* @return this {@link Registrar}.
|
||||
*/
|
||||
// TODO(amirh): Add a line in the javadoc above that points to a Platform Views website guide
|
||||
// when one is available (but not a website API doc)
|
||||
@NonNull
|
||||
Registrar addViewDestroyListener(@NonNull ViewDestroyListener listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate interface for handling result of permissions requests on behalf of the main {@link
|
||||
* Activity}.
|
||||
@ -412,29 +72,4 @@ public interface PluginRegistry {
|
||||
interface WindowFocusChangedListener {
|
||||
void onWindowFocusChanged(boolean hasFocus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate interface for handling an {@link android.app.Activity}'s onDestroy method being
|
||||
* called. A plugin that implements this interface can adopt the {@link FlutterNativeView} by
|
||||
* retaining a reference and returning true.
|
||||
*
|
||||
* @deprecated See https://flutter.dev/go/android-project-migration for migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
interface ViewDestroyListener {
|
||||
boolean onViewDestroy(@NonNull FlutterNativeView view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for registering plugins with a plugin registry.
|
||||
*
|
||||
* <p>For example, an Application may use this callback interface to provide a background service
|
||||
* with a callback for calling its GeneratedPluginRegistrant.registerWith method.
|
||||
*
|
||||
* @deprecated See https://flutter.dev/go/android-project-migration for migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
interface PluginRegistrantCallback {
|
||||
void registerWith(@NonNull PluginRegistry registry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ import java.util.ArrayList;
|
||||
/// The current editing state (text, selection range, composing range) the text input plugin holds.
|
||||
///
|
||||
/// As the name implies, this class also notifies its listeners when the editing state changes. When
|
||||
/// there're ongoing batch edits, change notifications will be deferred until all batch edits end
|
||||
/// there are ongoing batch edits, change notifications will be deferred until all batch edits end
|
||||
/// (i.e. when the outermost batch edit ends). Listeners added during a batch edit will always be
|
||||
/// notified when all batch edits end, even if there's no real change.
|
||||
///
|
||||
|
||||
@ -44,9 +44,8 @@ import java.util.List;
|
||||
/**
|
||||
* Manages platform views.
|
||||
*
|
||||
* <p>Each {@link io.flutter.embedding.engine.FlutterEngine} or {@link
|
||||
* io.flutter.app.FlutterPluginRegistry} has a single platform views controller. A platform views
|
||||
* controller can be attached to at most one Flutter view.
|
||||
* <p>Each {@link io.flutter.embedding.engine.FlutterEngine} has a single platform views controller.
|
||||
* A platform views controller can be attached to at most one Flutter view.
|
||||
*/
|
||||
public class PlatformViewsController implements PlatformViewsAccessibilityDelegate {
|
||||
private static final String TAG = "PlatformViewsController";
|
||||
|
||||
@ -1,132 +0,0 @@
|
||||
// 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.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import io.flutter.FlutterInjector;
|
||||
import io.flutter.embedding.engine.loader.FlutterLoader;
|
||||
|
||||
/**
|
||||
* A legacy class to initialize the Flutter engine.
|
||||
*
|
||||
* @deprecated Replaced by {@link io.flutter.embedding.engine.loader.FlutterLoader}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class FlutterMain {
|
||||
|
||||
public static class Settings {
|
||||
private String logTag;
|
||||
|
||||
@Nullable
|
||||
public String getLogTag() {
|
||||
return logTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tag associated with Flutter app log messages.
|
||||
*
|
||||
* @param tag Log tag.
|
||||
*/
|
||||
public void setLogTag(String tag) {
|
||||
logTag = tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts initialization of the native system.
|
||||
*
|
||||
* @param applicationContext The Android application context.
|
||||
*/
|
||||
public static void startInitialization(@NonNull Context applicationContext) {
|
||||
FlutterInjector.instance().flutterLoader().startInitialization(applicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts initialization of the native system.
|
||||
*
|
||||
* <p>This loads the Flutter engine's native library to enable subsequent JNI calls. This also
|
||||
* starts locating and unpacking Dart resources packaged in the app's APK.
|
||||
*
|
||||
* <p>Calling this method multiple times has no effect.
|
||||
*
|
||||
* @param applicationContext The Android application context.
|
||||
* @param settings Configuration settings.
|
||||
*/
|
||||
public static void startInitialization(
|
||||
@NonNull Context applicationContext, @NonNull Settings settings) {
|
||||
FlutterLoader.Settings newSettings = new FlutterLoader.Settings();
|
||||
newSettings.setLogTag(settings.getLogTag());
|
||||
FlutterInjector.instance().flutterLoader().startInitialization(applicationContext, newSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until initialization of the native system has completed.
|
||||
*
|
||||
* <p>Calling this method multiple times has no effect.
|
||||
*
|
||||
* @param applicationContext The Android application context.
|
||||
* @param args Flags sent to the Flutter runtime.
|
||||
*/
|
||||
public static void ensureInitializationComplete(
|
||||
@NonNull Context applicationContext, @Nullable String[] args) {
|
||||
FlutterInjector.instance()
|
||||
.flutterLoader()
|
||||
.ensureInitializationComplete(applicationContext, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #ensureInitializationComplete(Context, String[])} but waiting on a background
|
||||
* thread, then invoking {@code callback} on the {@code callbackHandler}.
|
||||
*/
|
||||
public static void ensureInitializationCompleteAsync(
|
||||
@NonNull Context applicationContext,
|
||||
@Nullable String[] args,
|
||||
@NonNull Handler callbackHandler,
|
||||
@NonNull Runnable callback) {
|
||||
FlutterInjector.instance()
|
||||
.flutterLoader()
|
||||
.ensureInitializationCompleteAsync(applicationContext, args, callbackHandler, callback);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String findAppBundlePath() {
|
||||
return FlutterInjector.instance().flutterLoader().findAppBundlePath();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public static String findAppBundlePath(@NonNull Context applicationContext) {
|
||||
return FlutterInjector.instance().flutterLoader().findAppBundlePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name for the given asset. The returned file name can be used to access the
|
||||
* asset in the APK through the {@link android.content.res.AssetManager} API.
|
||||
*
|
||||
* @param asset the name of the asset. The name can be hierarchical
|
||||
* @return the filename to be used with {@link android.content.res.AssetManager}
|
||||
*/
|
||||
@NonNull
|
||||
public static String getLookupKeyForAsset(@NonNull String asset) {
|
||||
return FlutterInjector.instance().flutterLoader().getLookupKeyForAsset(asset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name for the given asset which originates from the specified packageName. The
|
||||
* returned file name can be used to access the asset in the APK through the {@link
|
||||
* android.content.res.AssetManager} API.
|
||||
*
|
||||
* @param asset the name of the asset. The name can be hierarchical
|
||||
* @param packageName the name of the package from which the asset originates
|
||||
* @return the file name to be used with {@link android.content.res.AssetManager}
|
||||
*/
|
||||
@NonNull
|
||||
public static String getLookupKeyForAsset(@NonNull String asset, @NonNull String packageName) {
|
||||
return FlutterInjector.instance().flutterLoader().getLookupKeyForAsset(asset, packageName);
|
||||
}
|
||||
}
|
||||
@ -1,204 +0,0 @@
|
||||
// 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.view;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.UiThread;
|
||||
import io.flutter.Log;
|
||||
import io.flutter.app.FlutterPluginRegistry;
|
||||
import io.flutter.embedding.engine.FlutterEngine.EngineLifecycleListener;
|
||||
import io.flutter.embedding.engine.FlutterJNI;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.plugin.common.*;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @deprecated {@link io.flutter.embedding.android.FlutterView} is the new API that now replaces
|
||||
* this class. See https://flutter.dev/go/android-project-migration for more migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
public class FlutterNativeView implements BinaryMessenger {
|
||||
private static final String TAG = "FlutterNativeView";
|
||||
|
||||
private final FlutterPluginRegistry mPluginRegistry;
|
||||
private final DartExecutor dartExecutor;
|
||||
private FlutterView mFlutterView;
|
||||
private final FlutterJNI mFlutterJNI;
|
||||
private final Context mContext;
|
||||
private boolean applicationIsRunning;
|
||||
|
||||
private final FlutterUiDisplayListener flutterUiDisplayListener =
|
||||
new FlutterUiDisplayListener() {
|
||||
@Override
|
||||
public void onFlutterUiDisplayed() {
|
||||
if (mFlutterView == null) {
|
||||
return;
|
||||
}
|
||||
mFlutterView.onFirstFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
public FlutterNativeView(@NonNull Context context) {
|
||||
this(context, false);
|
||||
}
|
||||
|
||||
public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
|
||||
if (isBackgroundView) {
|
||||
Log.w(TAG, "'isBackgroundView' is no longer supported and will be ignored");
|
||||
}
|
||||
mContext = context;
|
||||
mPluginRegistry = new FlutterPluginRegistry(this, context);
|
||||
mFlutterJNI = new FlutterJNI();
|
||||
mFlutterJNI.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
this.dartExecutor = new DartExecutor(mFlutterJNI, context.getAssets());
|
||||
mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
|
||||
attach(this);
|
||||
assertAttached();
|
||||
}
|
||||
|
||||
public void detachFromFlutterView() {
|
||||
mPluginRegistry.detach();
|
||||
mFlutterView = null;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mPluginRegistry.destroy();
|
||||
dartExecutor.onDetachedFromJNI();
|
||||
mFlutterView = null;
|
||||
mFlutterJNI.removeIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
mFlutterJNI.detachFromNativeAndReleaseResources();
|
||||
applicationIsRunning = false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public DartExecutor getDartExecutor() {
|
||||
return dartExecutor;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public FlutterPluginRegistry getPluginRegistry() {
|
||||
return mPluginRegistry;
|
||||
}
|
||||
|
||||
public void attachViewAndActivity(FlutterView flutterView, Activity activity) {
|
||||
mFlutterView = flutterView;
|
||||
mPluginRegistry.attach(flutterView, activity);
|
||||
}
|
||||
|
||||
public boolean isAttached() {
|
||||
return mFlutterJNI.isAttached();
|
||||
}
|
||||
|
||||
public void assertAttached() {
|
||||
if (!isAttached()) throw new AssertionError("Platform view is not attached");
|
||||
}
|
||||
|
||||
public void runFromBundle(FlutterRunArguments args) {
|
||||
if (args.entrypoint == null) {
|
||||
throw new AssertionError("An entrypoint must be specified");
|
||||
}
|
||||
assertAttached();
|
||||
if (applicationIsRunning)
|
||||
throw new AssertionError("This Flutter engine instance is already running an application");
|
||||
mFlutterJNI.runBundleAndSnapshotFromLibrary(
|
||||
args.bundlePath,
|
||||
args.entrypoint,
|
||||
args.libraryPath,
|
||||
mContext.getResources().getAssets(),
|
||||
null);
|
||||
|
||||
applicationIsRunning = true;
|
||||
}
|
||||
|
||||
public boolean isApplicationRunning() {
|
||||
return applicationIsRunning;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getObservatoryUri() {
|
||||
return FlutterJNI.getVMServiceUri();
|
||||
}
|
||||
|
||||
public static String getVMServiceUri() {
|
||||
return FlutterJNI.getVMServiceUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public TaskQueue makeBackgroundTaskQueue(TaskQueueOptions options) {
|
||||
return dartExecutor.getBinaryMessenger().makeBackgroundTaskQueue(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void send(String channel, ByteBuffer message) {
|
||||
dartExecutor.getBinaryMessenger().send(channel, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void send(String channel, ByteBuffer message, BinaryReply callback) {
|
||||
if (!isAttached()) {
|
||||
Log.d(TAG, "FlutterView.send called on a detached view, channel=" + channel);
|
||||
return;
|
||||
}
|
||||
|
||||
dartExecutor.getBinaryMessenger().send(channel, message, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
|
||||
dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void setMessageHandler(String channel, BinaryMessageHandler handler, TaskQueue taskQueue) {
|
||||
dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler, taskQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableBufferingIncomingMessages() {}
|
||||
|
||||
@Override
|
||||
public void disableBufferingIncomingMessages() {}
|
||||
|
||||
/*package*/ FlutterJNI getFlutterJNI() {
|
||||
return mFlutterJNI;
|
||||
}
|
||||
|
||||
private void attach(FlutterNativeView view) {
|
||||
mFlutterJNI.attachToNative();
|
||||
dartExecutor.onAttachedToJNI();
|
||||
}
|
||||
|
||||
private final class EngineLifecycleListenerImpl implements EngineLifecycleListener {
|
||||
// Called by native to notify right before the engine is restarted (cold reload).
|
||||
@SuppressWarnings("unused")
|
||||
public void onPreEngineRestart() {
|
||||
if (mFlutterView != null) {
|
||||
mFlutterView.resetAccessibilityTree();
|
||||
}
|
||||
if (mPluginRegistry == null) {
|
||||
return;
|
||||
}
|
||||
mPluginRegistry.onPreEngineRestart();
|
||||
}
|
||||
|
||||
public void onEngineWillDestroy() {
|
||||
// The old embedding doesn't actually have a FlutterEngine. It interacts with the JNI
|
||||
// directly.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,997 +0,0 @@
|
||||
// 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.view;
|
||||
|
||||
import static io.flutter.Build.API_LEVELS;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PointerIcon;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewStructure;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityNodeProvider;
|
||||
import android.view.autofill.AutofillValue;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.window.BackEvent;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.UiThread;
|
||||
import io.flutter.Log;
|
||||
import io.flutter.app.FlutterPluginRegistry;
|
||||
import io.flutter.embedding.android.AndroidTouchProcessor;
|
||||
import io.flutter.embedding.android.KeyboardManager;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRenderer;
|
||||
import io.flutter.embedding.engine.renderer.SurfaceTextureWrapper;
|
||||
import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.BackGestureChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.LocalizationChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.NavigationChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.ScribeChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.SettingsChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.SystemChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.TextInputChannel;
|
||||
import io.flutter.plugin.common.ActivityLifecycleListener;
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.editing.TextInputPlugin;
|
||||
import io.flutter.plugin.localization.LocalizationPlugin;
|
||||
import io.flutter.plugin.mouse.MouseCursorPlugin;
|
||||
import io.flutter.plugin.platform.PlatformPlugin;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
import io.flutter.util.ViewUtils;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Deprecated Android view containing a Flutter app.
|
||||
*
|
||||
* @deprecated {@link io.flutter.embedding.android.FlutterView} is the new API that now replaces
|
||||
* this class. See https://flutter.dev/go/android-project-migration for more migration details.
|
||||
*/
|
||||
@Deprecated
|
||||
public class FlutterView extends SurfaceView
|
||||
implements BinaryMessenger,
|
||||
TextureRegistry,
|
||||
MouseCursorPlugin.MouseCursorViewDelegate,
|
||||
KeyboardManager.ViewDelegate {
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
public interface Provider {
|
||||
/**
|
||||
* Returns a reference to the Flutter view maintained by this object. This may be {@code null}.
|
||||
*
|
||||
* @return a reference to the Flutter view maintained by this object.
|
||||
*/
|
||||
FlutterView getFlutterView();
|
||||
}
|
||||
|
||||
private static final String TAG = "FlutterView";
|
||||
|
||||
static final class ViewportMetrics {
|
||||
float devicePixelRatio = 1.0f;
|
||||
int physicalWidth = 0;
|
||||
int physicalHeight = 0;
|
||||
int physicalViewPaddingTop = 0;
|
||||
int physicalViewPaddingRight = 0;
|
||||
int physicalViewPaddingBottom = 0;
|
||||
int physicalViewPaddingLeft = 0;
|
||||
int physicalViewInsetTop = 0;
|
||||
int physicalViewInsetRight = 0;
|
||||
int physicalViewInsetBottom = 0;
|
||||
int physicalViewInsetLeft = 0;
|
||||
int systemGestureInsetTop = 0;
|
||||
int systemGestureInsetRight = 0;
|
||||
int systemGestureInsetBottom = 0;
|
||||
int systemGestureInsetLeft = 0;
|
||||
int physicalTouchSlop = -1;
|
||||
}
|
||||
|
||||
private final DartExecutor dartExecutor;
|
||||
private final FlutterRenderer flutterRenderer;
|
||||
private final NavigationChannel navigationChannel;
|
||||
private final BackGestureChannel backGestureChannel;
|
||||
private final LifecycleChannel lifecycleChannel;
|
||||
private final LocalizationChannel localizationChannel;
|
||||
private final PlatformChannel platformChannel;
|
||||
private final SettingsChannel settingsChannel;
|
||||
private final SystemChannel systemChannel;
|
||||
private final InputMethodManager mImm;
|
||||
private final TextInputPlugin mTextInputPlugin;
|
||||
private final LocalizationPlugin mLocalizationPlugin;
|
||||
private final MouseCursorPlugin mMouseCursorPlugin;
|
||||
private final KeyboardManager mKeyboardManager;
|
||||
private final AndroidTouchProcessor androidTouchProcessor;
|
||||
private AccessibilityBridge mAccessibilityNodeProvider;
|
||||
private final SurfaceHolder.Callback mSurfaceCallback;
|
||||
private final ViewportMetrics mMetrics;
|
||||
private final List<ActivityLifecycleListener> mActivityLifecycleListeners;
|
||||
private final List<FirstFrameListener> mFirstFrameListeners;
|
||||
private final AtomicLong nextTextureId = new AtomicLong(0L);
|
||||
private FlutterNativeView mNativeView;
|
||||
private boolean mIsSoftwareRenderingEnabled = false; // using the software renderer or not
|
||||
private boolean didRenderFirstFrame = false;
|
||||
|
||||
private final AccessibilityBridge.OnAccessibilityChangeListener onAccessibilityChangeListener =
|
||||
new AccessibilityBridge.OnAccessibilityChangeListener() {
|
||||
@Override
|
||||
public void onAccessibilityChanged(
|
||||
boolean isAccessibilityEnabled, boolean isTouchExplorationEnabled) {
|
||||
resetWillNotDraw(isAccessibilityEnabled, isTouchExplorationEnabled);
|
||||
}
|
||||
};
|
||||
|
||||
public FlutterView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public FlutterView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, null);
|
||||
}
|
||||
|
||||
public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
|
||||
super(context, attrs);
|
||||
|
||||
Activity activity = ViewUtils.getActivity(getContext());
|
||||
if (activity == null) {
|
||||
throw new IllegalArgumentException("Bad context");
|
||||
}
|
||||
|
||||
if (nativeView == null) {
|
||||
mNativeView = new FlutterNativeView(activity.getApplicationContext());
|
||||
} else {
|
||||
mNativeView = nativeView;
|
||||
}
|
||||
|
||||
dartExecutor = mNativeView.getDartExecutor();
|
||||
flutterRenderer = new FlutterRenderer(mNativeView.getFlutterJNI());
|
||||
mIsSoftwareRenderingEnabled = mNativeView.getFlutterJNI().getIsSoftwareRenderingEnabled();
|
||||
mMetrics = new ViewportMetrics();
|
||||
mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
|
||||
mMetrics.physicalTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
|
||||
mNativeView.attachViewAndActivity(this, activity);
|
||||
|
||||
mSurfaceCallback =
|
||||
new SurfaceHolder.Callback() {
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
assertAttached();
|
||||
mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
assertAttached();
|
||||
mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
assertAttached();
|
||||
mNativeView.getFlutterJNI().onSurfaceDestroyed();
|
||||
}
|
||||
};
|
||||
getHolder().addCallback(mSurfaceCallback);
|
||||
|
||||
mActivityLifecycleListeners = new ArrayList<>();
|
||||
mFirstFrameListeners = new ArrayList<>();
|
||||
|
||||
// Create all platform channels
|
||||
navigationChannel = new NavigationChannel(dartExecutor);
|
||||
backGestureChannel = new BackGestureChannel(dartExecutor);
|
||||
lifecycleChannel = new LifecycleChannel(dartExecutor);
|
||||
localizationChannel = new LocalizationChannel(dartExecutor);
|
||||
platformChannel = new PlatformChannel(dartExecutor);
|
||||
systemChannel = new SystemChannel(dartExecutor);
|
||||
settingsChannel = new SettingsChannel(dartExecutor);
|
||||
|
||||
// Create and set up plugins
|
||||
PlatformPlugin platformPlugin = new PlatformPlugin(activity, platformChannel);
|
||||
addActivityLifecycleListener(
|
||||
new ActivityLifecycleListener() {
|
||||
@Override
|
||||
public void onPostResume() {
|
||||
platformPlugin.updateSystemUiOverlays();
|
||||
}
|
||||
});
|
||||
mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
PlatformViewsController platformViewsController =
|
||||
mNativeView.getPluginRegistry().getPlatformViewsController();
|
||||
mTextInputPlugin =
|
||||
new TextInputPlugin(
|
||||
this,
|
||||
new TextInputChannel(dartExecutor),
|
||||
new ScribeChannel(dartExecutor),
|
||||
platformViewsController);
|
||||
mKeyboardManager = new KeyboardManager(this);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= API_LEVELS.API_24) {
|
||||
mMouseCursorPlugin = new MouseCursorPlugin(this, new MouseCursorChannel(dartExecutor));
|
||||
} else {
|
||||
mMouseCursorPlugin = null;
|
||||
}
|
||||
mLocalizationPlugin = new LocalizationPlugin(context, localizationChannel);
|
||||
androidTouchProcessor =
|
||||
new AndroidTouchProcessor(flutterRenderer, /*trackMotionEvents=*/ false);
|
||||
platformViewsController.attachToFlutterRenderer(flutterRenderer);
|
||||
mNativeView
|
||||
.getPluginRegistry()
|
||||
.getPlatformViewsController()
|
||||
.attachTextInputPlugin(mTextInputPlugin);
|
||||
mNativeView.getFlutterJNI().setLocalizationPlugin(mLocalizationPlugin);
|
||||
|
||||
// Send initial platform information to Dart
|
||||
mLocalizationPlugin.sendLocalesToFlutter(getResources().getConfiguration());
|
||||
sendUserPlatformSettingsToDart();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public DartExecutor getDartExecutor() {
|
||||
return dartExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
Log.e(TAG, "dispatchKeyEvent: " + event.toString());
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
|
||||
// Tell Android to start tracking this event.
|
||||
getKeyDispatcherState().startTracking(event, this);
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
// Stop tracking the event.
|
||||
getKeyDispatcherState().handleUpEvent(event);
|
||||
}
|
||||
// If the key processor doesn't handle it, then send it on to the
|
||||
// superclass. The key processor will typically handle all events except
|
||||
// those where it has re-dispatched the event after receiving a reply from
|
||||
// the framework that the framework did not handle it.
|
||||
return (isAttached() && mKeyboardManager.handleEvent(event)) || super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
public FlutterNativeView getFlutterNativeView() {
|
||||
return mNativeView;
|
||||
}
|
||||
|
||||
public FlutterPluginRegistry getPluginRegistry() {
|
||||
return mNativeView.getPluginRegistry();
|
||||
}
|
||||
|
||||
public String getLookupKeyForAsset(String asset) {
|
||||
return FlutterMain.getLookupKeyForAsset(asset);
|
||||
}
|
||||
|
||||
public String getLookupKeyForAsset(String asset, String packageName) {
|
||||
return FlutterMain.getLookupKeyForAsset(asset, packageName);
|
||||
}
|
||||
|
||||
public void addActivityLifecycleListener(ActivityLifecycleListener listener) {
|
||||
mActivityLifecycleListeners.add(listener);
|
||||
}
|
||||
|
||||
public void onStart() {
|
||||
lifecycleChannel.appIsInactive();
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
lifecycleChannel.appIsInactive();
|
||||
}
|
||||
|
||||
public void onPostResume() {
|
||||
for (ActivityLifecycleListener listener : mActivityLifecycleListeners) {
|
||||
listener.onPostResume();
|
||||
}
|
||||
lifecycleChannel.appIsResumed();
|
||||
}
|
||||
|
||||
public void onStop() {
|
||||
lifecycleChannel.appIsPaused();
|
||||
}
|
||||
|
||||
public void onMemoryPressure() {
|
||||
mNativeView.getFlutterJNI().notifyLowMemoryWarning();
|
||||
systemChannel.sendMemoryPressureWarning();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Flutter experience associated with this {@code FlutterView} has rendered
|
||||
* its first frame, or false otherwise.
|
||||
*/
|
||||
public boolean hasRenderedFirstFrame() {
|
||||
return didRenderFirstFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/** Remove an existing first frame listener. */
|
||||
public void removeFirstFrameListener(FirstFrameListener listener) {
|
||||
mFirstFrameListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableBufferingIncomingMessages() {}
|
||||
|
||||
@Override
|
||||
public void disableBufferingIncomingMessages() {}
|
||||
|
||||
/**
|
||||
* Reverts this back to the {@link SurfaceView} defaults, at the back of its window and opaque.
|
||||
*/
|
||||
public void disableTransparentBackground() {
|
||||
setZOrderOnTop(false);
|
||||
getHolder().setFormat(PixelFormat.OPAQUE);
|
||||
}
|
||||
|
||||
public void setInitialRoute(String route) {
|
||||
navigationChannel.setInitialRoute(route);
|
||||
}
|
||||
|
||||
public void pushRoute(String route) {
|
||||
navigationChannel.pushRoute(route);
|
||||
}
|
||||
|
||||
public void popRoute() {
|
||||
navigationChannel.popRoute();
|
||||
}
|
||||
|
||||
@TargetApi(API_LEVELS.API_34)
|
||||
@RequiresApi(API_LEVELS.API_34)
|
||||
public void startBackGesture(@NonNull BackEvent backEvent) {
|
||||
backGestureChannel.startBackGesture(backEvent);
|
||||
}
|
||||
|
||||
@TargetApi(API_LEVELS.API_34)
|
||||
@RequiresApi(API_LEVELS.API_34)
|
||||
public void updateBackGestureProgress(@NonNull BackEvent backEvent) {
|
||||
backGestureChannel.updateBackGestureProgress(backEvent);
|
||||
}
|
||||
|
||||
@TargetApi(API_LEVELS.API_34)
|
||||
@RequiresApi(API_LEVELS.API_34)
|
||||
public void commitBackGesture() {
|
||||
backGestureChannel.commitBackGesture();
|
||||
}
|
||||
|
||||
@TargetApi(API_LEVELS.API_34)
|
||||
@RequiresApi(API_LEVELS.API_34)
|
||||
public void cancelBackGesture() {
|
||||
backGestureChannel.cancelBackGesture();
|
||||
}
|
||||
|
||||
private void sendUserPlatformSettingsToDart() {
|
||||
// Lookup the current brightness of the Android OS.
|
||||
boolean isNightModeOn =
|
||||
(getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
|
||||
== Configuration.UI_MODE_NIGHT_YES;
|
||||
SettingsChannel.PlatformBrightness brightness =
|
||||
isNightModeOn
|
||||
? SettingsChannel.PlatformBrightness.dark
|
||||
: SettingsChannel.PlatformBrightness.light;
|
||||
|
||||
settingsChannel
|
||||
.startMessage()
|
||||
.setTextScaleFactor(getResources().getConfiguration().fontScale)
|
||||
.setUse24HourFormat(DateFormat.is24HourFormat(getContext()))
|
||||
.setPlatformBrightness(brightness)
|
||||
.send();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
mLocalizationPlugin.sendLocalesToFlutter(newConfig);
|
||||
sendUserPlatformSettingsToDart();
|
||||
}
|
||||
|
||||
float getDevicePixelRatio() {
|
||||
return mMetrics.devicePixelRatio;
|
||||
}
|
||||
|
||||
public FlutterNativeView detach() {
|
||||
if (!isAttached()) return null;
|
||||
getHolder().removeCallback(mSurfaceCallback);
|
||||
mNativeView.detachFromFlutterView();
|
||||
|
||||
FlutterNativeView view = mNativeView;
|
||||
mNativeView = null;
|
||||
return view;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (!isAttached()) return;
|
||||
|
||||
getHolder().removeCallback(mSurfaceCallback);
|
||||
releaseAccessibilityNodeProvider();
|
||||
|
||||
mNativeView.destroy();
|
||||
mNativeView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
return mTextInputPlugin.createInputConnection(this, mKeyboardManager, outAttrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkInputConnectionProxy(View view) {
|
||||
return mNativeView
|
||||
.getPluginRegistry()
|
||||
.getPlatformViewsController()
|
||||
.checkInputConnectionProxy(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
|
||||
super.onProvideAutofillVirtualStructure(structure, flags);
|
||||
mTextInputPlugin.onProvideAutofillVirtualStructure(structure, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void autofill(SparseArray<AutofillValue> values) {
|
||||
mTextInputPlugin.autofill(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (!isAttached()) {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
requestUnbufferedDispatch(event);
|
||||
|
||||
return androidTouchProcessor.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHoverEvent(MotionEvent event) {
|
||||
if (!isAttached()) {
|
||||
return super.onHoverEvent(event);
|
||||
}
|
||||
|
||||
boolean handled = mAccessibilityNodeProvider.onAccessibilityHoverEvent(event);
|
||||
if (!handled) {
|
||||
// TODO(ianh): Expose hover events to the platform,
|
||||
// implementing ADD, REMOVE, etc.
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by Android when a generic motion event occurs, e.g., joystick movement, mouse hover,
|
||||
* track pad touches, scroll wheel movements, etc.
|
||||
*
|
||||
* <p>Flutter handles all of its own gesture detection and processing, therefore this method
|
||||
* forwards all {@link MotionEvent} data from Android to Flutter.
|
||||
*/
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
boolean handled =
|
||||
isAttached() && androidTouchProcessor.onGenericMotionEvent(event, getContext());
|
||||
return handled ? true : super.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
|
||||
mMetrics.physicalWidth = width;
|
||||
mMetrics.physicalHeight = height;
|
||||
updateViewportMetrics();
|
||||
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
||||
}
|
||||
|
||||
// TODO(garyq): Add support for notch cutout API
|
||||
// Decide if we want to zero the padding of the sides. When in Landscape orientation,
|
||||
// android may decide to place the software navigation bars on the side. When the nav
|
||||
// bar is hidden, the reported insets should be removed to prevent extra useless space
|
||||
// on the sides.
|
||||
private enum ZeroSides {
|
||||
NONE,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
BOTH
|
||||
}
|
||||
|
||||
private ZeroSides calculateShouldZeroSides() {
|
||||
// We get both orientation and rotation because rotation is all 4
|
||||
// rotations relative to default rotation while orientation is portrait
|
||||
// or landscape. By combining both, we can obtain a more precise measure
|
||||
// of the rotation.
|
||||
Context context = getContext();
|
||||
int orientation = context.getResources().getConfiguration().orientation;
|
||||
int rotation =
|
||||
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
|
||||
.getDefaultDisplay()
|
||||
.getRotation();
|
||||
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
if (rotation == Surface.ROTATION_90) {
|
||||
return ZeroSides.RIGHT;
|
||||
} else if (rotation == Surface.ROTATION_270) {
|
||||
// In android API >= 23, the nav bar always appears on the "bottom" (USB) side.
|
||||
return Build.VERSION.SDK_INT >= API_LEVELS.API_23 ? ZeroSides.LEFT : ZeroSides.RIGHT;
|
||||
}
|
||||
// Ambiguous orientation due to landscape left/right default. Zero both sides.
|
||||
else if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
|
||||
return ZeroSides.BOTH;
|
||||
}
|
||||
}
|
||||
// Square orientation deprecated in API 16, we will not check for it and return false
|
||||
// to be safe and not remove any unique padding for the devices that do use it.
|
||||
return ZeroSides.NONE;
|
||||
}
|
||||
|
||||
// TODO(garyq): Use new Android R getInsets API
|
||||
// TODO(garyq): The keyboard detection may interact strangely with
|
||||
// https://github.com/flutter/flutter/issues/22061
|
||||
|
||||
// Uses inset heights and screen heights as a heuristic to determine if the insets should
|
||||
// be padded. When the on-screen keyboard is detected, we want to include the full inset
|
||||
// but when the inset is just the hidden nav bar, we want to provide a zero inset so the space
|
||||
// can be used.
|
||||
|
||||
private int guessBottomKeyboardInset(WindowInsets insets) {
|
||||
int screenHeight = getRootView().getHeight();
|
||||
// Magic number due to this being a heuristic. This should be replaced, but we have not
|
||||
// found a clean way to do it yet (Sept. 2018)
|
||||
final double keyboardHeightRatioHeuristic = 0.18;
|
||||
if (insets.getSystemWindowInsetBottom() < screenHeight * keyboardHeightRatioHeuristic) {
|
||||
// Is not a keyboard, so return zero as inset.
|
||||
return 0;
|
||||
} else {
|
||||
// Is a keyboard, so return the full inset.
|
||||
return insets.getSystemWindowInsetBottom();
|
||||
}
|
||||
}
|
||||
|
||||
// This callback is not present in API < 20, which means lower API devices will see
|
||||
// the wider than expected padding when the status and navigation bars are hidden.
|
||||
// The annotations to suppress "InlinedApi" and "NewApi" lints prevent lint warnings
|
||||
// caused by usage of Android Q APIs. These calls are safe because they are
|
||||
// guarded.
|
||||
@Override
|
||||
@SuppressLint({"InlinedApi", "NewApi"})
|
||||
public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||
// getSystemGestureInsets() was introduced in API 29 and immediately deprecated in 30.
|
||||
if (Build.VERSION.SDK_INT == API_LEVELS.API_29) {
|
||||
Insets systemGestureInsets = insets.getSystemGestureInsets();
|
||||
mMetrics.systemGestureInsetTop = systemGestureInsets.top;
|
||||
mMetrics.systemGestureInsetRight = systemGestureInsets.right;
|
||||
mMetrics.systemGestureInsetBottom = systemGestureInsets.bottom;
|
||||
mMetrics.systemGestureInsetLeft = systemGestureInsets.left;
|
||||
}
|
||||
|
||||
boolean statusBarVisible = (SYSTEM_UI_FLAG_FULLSCREEN & getWindowSystemUiVisibility()) == 0;
|
||||
boolean navigationBarVisible =
|
||||
(SYSTEM_UI_FLAG_HIDE_NAVIGATION & getWindowSystemUiVisibility()) == 0;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= API_LEVELS.API_30) {
|
||||
int mask = 0;
|
||||
if (navigationBarVisible) {
|
||||
mask = mask | android.view.WindowInsets.Type.navigationBars();
|
||||
}
|
||||
if (statusBarVisible) {
|
||||
mask = mask | android.view.WindowInsets.Type.statusBars();
|
||||
}
|
||||
Insets uiInsets = insets.getInsets(mask);
|
||||
mMetrics.physicalViewPaddingTop = uiInsets.top;
|
||||
mMetrics.physicalViewPaddingRight = uiInsets.right;
|
||||
mMetrics.physicalViewPaddingBottom = uiInsets.bottom;
|
||||
mMetrics.physicalViewPaddingLeft = uiInsets.left;
|
||||
|
||||
Insets imeInsets = insets.getInsets(android.view.WindowInsets.Type.ime());
|
||||
mMetrics.physicalViewInsetTop = imeInsets.top;
|
||||
mMetrics.physicalViewInsetRight = imeInsets.right;
|
||||
mMetrics.physicalViewInsetBottom = imeInsets.bottom; // Typically, only bottom is non-zero
|
||||
mMetrics.physicalViewInsetLeft = imeInsets.left;
|
||||
|
||||
Insets systemGestureInsets =
|
||||
insets.getInsets(android.view.WindowInsets.Type.systemGestures());
|
||||
mMetrics.systemGestureInsetTop = systemGestureInsets.top;
|
||||
mMetrics.systemGestureInsetRight = systemGestureInsets.right;
|
||||
mMetrics.systemGestureInsetBottom = systemGestureInsets.bottom;
|
||||
mMetrics.systemGestureInsetLeft = systemGestureInsets.left;
|
||||
|
||||
// TODO(garyq): Expose the full rects of the display cutout.
|
||||
|
||||
// Take the max of the display cutout insets and existing padding to merge them
|
||||
DisplayCutout cutout = insets.getDisplayCutout();
|
||||
if (cutout != null) {
|
||||
Insets waterfallInsets = cutout.getWaterfallInsets();
|
||||
mMetrics.physicalViewPaddingTop =
|
||||
Math.max(
|
||||
Math.max(mMetrics.physicalViewPaddingTop, waterfallInsets.top),
|
||||
cutout.getSafeInsetTop());
|
||||
mMetrics.physicalViewPaddingRight =
|
||||
Math.max(
|
||||
Math.max(mMetrics.physicalViewPaddingRight, waterfallInsets.right),
|
||||
cutout.getSafeInsetRight());
|
||||
mMetrics.physicalViewPaddingBottom =
|
||||
Math.max(
|
||||
Math.max(mMetrics.physicalViewPaddingBottom, waterfallInsets.bottom),
|
||||
cutout.getSafeInsetBottom());
|
||||
mMetrics.physicalViewPaddingLeft =
|
||||
Math.max(
|
||||
Math.max(mMetrics.physicalViewPaddingLeft, waterfallInsets.left),
|
||||
cutout.getSafeInsetLeft());
|
||||
}
|
||||
} else {
|
||||
// We zero the left and/or right sides to prevent the padding the
|
||||
// navigation bar would have caused.
|
||||
ZeroSides zeroSides = ZeroSides.NONE;
|
||||
if (!navigationBarVisible) {
|
||||
zeroSides = calculateShouldZeroSides();
|
||||
}
|
||||
|
||||
// Status bar (top), navigation bar (bottom) and left/right system insets should
|
||||
// partially obscure the content (padding).
|
||||
mMetrics.physicalViewPaddingTop = statusBarVisible ? insets.getSystemWindowInsetTop() : 0;
|
||||
mMetrics.physicalViewPaddingRight =
|
||||
zeroSides == ZeroSides.RIGHT || zeroSides == ZeroSides.BOTH
|
||||
? 0
|
||||
: insets.getSystemWindowInsetRight();
|
||||
mMetrics.physicalViewPaddingBottom =
|
||||
navigationBarVisible && guessBottomKeyboardInset(insets) == 0
|
||||
? insets.getSystemWindowInsetBottom()
|
||||
: 0;
|
||||
mMetrics.physicalViewPaddingLeft =
|
||||
zeroSides == ZeroSides.LEFT || zeroSides == ZeroSides.BOTH
|
||||
? 0
|
||||
: insets.getSystemWindowInsetLeft();
|
||||
|
||||
// Bottom system inset (keyboard) should adjust scrollable bottom edge (inset).
|
||||
mMetrics.physicalViewInsetTop = 0;
|
||||
mMetrics.physicalViewInsetRight = 0;
|
||||
mMetrics.physicalViewInsetBottom = guessBottomKeyboardInset(insets);
|
||||
mMetrics.physicalViewInsetLeft = 0;
|
||||
}
|
||||
|
||||
updateViewportMetrics();
|
||||
return super.onApplyWindowInsets(insets);
|
||||
}
|
||||
|
||||
private boolean isAttached() {
|
||||
return mNativeView != null && mNativeView.isAttached();
|
||||
}
|
||||
|
||||
void assertAttached() {
|
||||
if (!isAttached()) throw new AssertionError("Platform view is not attached");
|
||||
}
|
||||
|
||||
private void preRun() {
|
||||
resetAccessibilityTree();
|
||||
}
|
||||
|
||||
void resetAccessibilityTree() {
|
||||
if (mAccessibilityNodeProvider != null) {
|
||||
mAccessibilityNodeProvider.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private void postRun() {}
|
||||
|
||||
public void runFromBundle(FlutterRunArguments args) {
|
||||
assertAttached();
|
||||
preRun();
|
||||
mNativeView.runFromBundle(args);
|
||||
postRun();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the most recent frame as a bitmap.
|
||||
*
|
||||
* @return A bitmap.
|
||||
*/
|
||||
public Bitmap getBitmap() {
|
||||
assertAttached();
|
||||
return mNativeView.getFlutterJNI().getBitmap();
|
||||
}
|
||||
|
||||
private void updateViewportMetrics() {
|
||||
if (!isAttached()) return;
|
||||
mNativeView
|
||||
.getFlutterJNI()
|
||||
.setViewportMetrics(
|
||||
mMetrics.devicePixelRatio,
|
||||
mMetrics.physicalWidth,
|
||||
mMetrics.physicalHeight,
|
||||
mMetrics.physicalViewPaddingTop,
|
||||
mMetrics.physicalViewPaddingRight,
|
||||
mMetrics.physicalViewPaddingBottom,
|
||||
mMetrics.physicalViewPaddingLeft,
|
||||
mMetrics.physicalViewInsetTop,
|
||||
mMetrics.physicalViewInsetRight,
|
||||
mMetrics.physicalViewInsetBottom,
|
||||
mMetrics.physicalViewInsetLeft,
|
||||
mMetrics.systemGestureInsetTop,
|
||||
mMetrics.systemGestureInsetRight,
|
||||
mMetrics.systemGestureInsetBottom,
|
||||
mMetrics.systemGestureInsetLeft,
|
||||
mMetrics.physicalTouchSlop,
|
||||
new int[0],
|
||||
new int[0],
|
||||
new int[0]);
|
||||
}
|
||||
|
||||
// Called by FlutterNativeView to notify first Flutter frame rendered.
|
||||
public void onFirstFrame() {
|
||||
didRenderFirstFrame = true;
|
||||
|
||||
// Allow listeners to remove themselves when they are called.
|
||||
List<FirstFrameListener> listeners = new ArrayList<>(mFirstFrameListeners);
|
||||
for (FirstFrameListener listener : listeners) {
|
||||
listener.onFirstFrame();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
PlatformViewsController platformViewsController =
|
||||
getPluginRegistry().getPlatformViewsController();
|
||||
mAccessibilityNodeProvider =
|
||||
new AccessibilityBridge(
|
||||
this,
|
||||
new AccessibilityChannel(dartExecutor, getFlutterNativeView().getFlutterJNI()),
|
||||
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE),
|
||||
getContext().getContentResolver(),
|
||||
platformViewsController);
|
||||
mAccessibilityNodeProvider.setOnAccessibilityChangeListener(onAccessibilityChangeListener);
|
||||
|
||||
resetWillNotDraw(
|
||||
mAccessibilityNodeProvider.isAccessibilityEnabled(),
|
||||
mAccessibilityNodeProvider.isTouchExplorationEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
releaseAccessibilityNodeProvider();
|
||||
}
|
||||
|
||||
// TODO(mattcarroll): Confer with Ian as to why we need this method. Delete if possible, otherwise
|
||||
// add comments.
|
||||
private void resetWillNotDraw(boolean isAccessibilityEnabled, boolean isTouchExplorationEnabled) {
|
||||
if (!mIsSoftwareRenderingEnabled) {
|
||||
setWillNotDraw(!(isAccessibilityEnabled || isTouchExplorationEnabled));
|
||||
} else {
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeProvider getAccessibilityNodeProvider() {
|
||||
if (mAccessibilityNodeProvider != null && mAccessibilityNodeProvider.isAccessibilityEnabled()) {
|
||||
return mAccessibilityNodeProvider;
|
||||
} else {
|
||||
// TODO(goderbauer): when a11y is off this should return a one-off snapshot of
|
||||
// the a11y
|
||||
// tree.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseAccessibilityNodeProvider() {
|
||||
if (mAccessibilityNodeProvider != null) {
|
||||
mAccessibilityNodeProvider.release();
|
||||
mAccessibilityNodeProvider = null;
|
||||
}
|
||||
}
|
||||
|
||||
// -------- Start: Mouse -------
|
||||
|
||||
@Override
|
||||
@TargetApi(API_LEVELS.API_24)
|
||||
@RequiresApi(API_LEVELS.API_24)
|
||||
@NonNull
|
||||
public PointerIcon getSystemPointerIcon(int type) {
|
||||
return PointerIcon.getSystemIcon(getContext(), type);
|
||||
}
|
||||
|
||||
// -------- End: Mouse -------
|
||||
|
||||
// -------- Start: Keyboard -------
|
||||
|
||||
@Override
|
||||
public BinaryMessenger getBinaryMessenger() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTextInputKeyEvent(@NonNull KeyEvent keyEvent) {
|
||||
return mTextInputPlugin.handleKeyEvent(keyEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redispatch(@NonNull KeyEvent keyEvent) {
|
||||
getRootView().dispatchKeyEvent(keyEvent);
|
||||
}
|
||||
|
||||
// -------- End: Keyboard -------
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public TaskQueue makeBackgroundTaskQueue(TaskQueueOptions options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void send(String channel, ByteBuffer message) {
|
||||
send(channel, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void send(String channel, ByteBuffer message, BinaryReply callback) {
|
||||
if (!isAttached()) {
|
||||
Log.d(TAG, "FlutterView.send called on a detached view, channel=" + channel);
|
||||
return;
|
||||
}
|
||||
mNativeView.send(channel, message, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void setMessageHandler(@NonNull String channel, @NonNull BinaryMessageHandler handler) {
|
||||
mNativeView.setMessageHandler(channel, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void setMessageHandler(
|
||||
@NonNull String channel,
|
||||
@NonNull BinaryMessageHandler handler,
|
||||
@NonNull TaskQueue taskQueue) {
|
||||
mNativeView.setMessageHandler(channel, handler, taskQueue);
|
||||
}
|
||||
|
||||
/** Listener will be called on the Android UI thread once when Flutter renders the first frame. */
|
||||
public interface FirstFrameListener {
|
||||
void onFirstFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public TextureRegistry.SurfaceTextureEntry createSurfaceTexture() {
|
||||
final SurfaceTexture surfaceTexture = new SurfaceTexture(0);
|
||||
return registerSurfaceTexture(surfaceTexture);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public ImageTextureEntry createImageTexture() {
|
||||
throw new UnsupportedOperationException("Image textures are not supported in this mode.");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SurfaceProducer createSurfaceProducer() {
|
||||
throw new UnsupportedOperationException(
|
||||
"SurfaceProducer textures are not supported in this mode.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public TextureRegistry.SurfaceTextureEntry registerSurfaceTexture(
|
||||
@NonNull SurfaceTexture surfaceTexture) {
|
||||
surfaceTexture.detachFromGLContext();
|
||||
final SurfaceTextureRegistryEntry entry =
|
||||
new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(), surfaceTexture);
|
||||
mNativeView.getFlutterJNI().registerTexture(entry.id(), entry.textureWrapper());
|
||||
return entry;
|
||||
}
|
||||
|
||||
final class SurfaceTextureRegistryEntry implements TextureRegistry.SurfaceTextureEntry {
|
||||
private final long id;
|
||||
private final SurfaceTextureWrapper textureWrapper;
|
||||
private boolean released;
|
||||
|
||||
SurfaceTextureRegistryEntry(long id, SurfaceTexture surfaceTexture) {
|
||||
this.id = id;
|
||||
this.textureWrapper = new SurfaceTextureWrapper(surfaceTexture);
|
||||
|
||||
// The callback relies on being executed on the UI thread (unsynchronised read of
|
||||
// mNativeView
|
||||
// and also the engine code check for platform thread in
|
||||
// Shell::OnPlatformViewMarkTextureFrameAvailable),
|
||||
// so we explicitly pass a Handler for the current thread.
|
||||
this.surfaceTexture().setOnFrameAvailableListener(onFrameListener, new Handler());
|
||||
}
|
||||
|
||||
private SurfaceTexture.OnFrameAvailableListener onFrameListener =
|
||||
new SurfaceTexture.OnFrameAvailableListener() {
|
||||
@Override
|
||||
public void onFrameAvailable(SurfaceTexture texture) {
|
||||
if (released || mNativeView == null) {
|
||||
// Even though we make sure to unregister the callback before releasing, as of Android
|
||||
// O
|
||||
// SurfaceTexture has a data race when accessing the callback, so the callback may
|
||||
// still be called by a stale reference after released==true and mNativeView==null.
|
||||
return;
|
||||
}
|
||||
|
||||
mNativeView
|
||||
.getFlutterJNI()
|
||||
.markTextureFrameAvailable(SurfaceTextureRegistryEntry.this.id);
|
||||
}
|
||||
};
|
||||
|
||||
public SurfaceTextureWrapper textureWrapper() {
|
||||
return textureWrapper;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SurfaceTexture surfaceTexture() {
|
||||
return textureWrapper.surfaceTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
if (released) {
|
||||
return;
|
||||
}
|
||||
released = true;
|
||||
|
||||
// The ordering of the next 3 calls is important:
|
||||
// First we remove the frame listener, then we release the SurfaceTexture, and only after we
|
||||
// unregister
|
||||
// the texture which actually deletes the GL texture.
|
||||
|
||||
// Otherwise onFrameAvailableListener might be called after mNativeView==null
|
||||
// (https://github.com/flutter/flutter/issues/20951). See also the check in onFrameAvailable.
|
||||
surfaceTexture().setOnFrameAvailableListener(null);
|
||||
textureWrapper.release();
|
||||
mNativeView.getFlutterJNI().unregisterTexture(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,8 +13,8 @@ import androidx.annotation.Nullable;
|
||||
|
||||
// TODO(mattcarroll): re-evalute docs in this class and add nullability annotations.
|
||||
/**
|
||||
* Registry of backend textures used with a single {@link FlutterView} instance. Entries may be
|
||||
* embedded into the Flutter view using the <a
|
||||
* Registry of backend textures used with a single {@link io.flutter.embedding.android.FlutterView}
|
||||
* instance. Entries may be embedded into the Flutter view using the <a
|
||||
* href="https://api.flutter.dev/flutter/widgets/Texture-class.html">Texture</a> widget.
|
||||
*/
|
||||
public interface TextureRegistry {
|
||||
|
||||
@ -1,157 +0,0 @@
|
||||
// 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.plugins.shim;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding;
|
||||
import io.flutter.embedding.engine.plugins.PluginRegistry;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@Config(manifest = Config.NONE)
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ShimPluginRegistryTest {
|
||||
|
||||
@Mock private FlutterEngine mockFlutterEngine;
|
||||
@Mock private FlutterPluginBinding mockFlutterPluginBinding;
|
||||
@Mock private ActivityPluginBinding mockActivityPluginBinding;
|
||||
@Mock private PluginRegistry mockPluginRegistry;
|
||||
@Mock private Context mockApplicationContext;
|
||||
@Mock private Activity mockActivity;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
when(mockFlutterEngine.getPlugins()).thenReturn(mockPluginRegistry);
|
||||
when(mockFlutterPluginBinding.getApplicationContext()).thenReturn(mockApplicationContext);
|
||||
when(mockActivityPluginBinding.getActivity()).thenReturn(mockActivity);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
// Test is intentionally verifying deprecated behavior.
|
||||
@Test
|
||||
public void itSuppliesOldAPIsViaTheNewFlutterPluginBinding() {
|
||||
ShimPluginRegistry registryUnderTest = new ShimPluginRegistry(mockFlutterEngine);
|
||||
// Fully qualifed name because imports can not have deprecation supression.
|
||||
// This is the consumption side of the old plugins.
|
||||
io.flutter.plugin.common.PluginRegistry.Registrar registrarUnderTest =
|
||||
registryUnderTest.registrarFor("test");
|
||||
|
||||
ArgumentCaptor<FlutterPlugin> shimAggregateCaptor =
|
||||
ArgumentCaptor.forClass(FlutterPlugin.class);
|
||||
// A single shim aggregate was added as a new plugin to the FlutterEngine's PluginRegistry.
|
||||
verify(mockPluginRegistry).add(shimAggregateCaptor.capture());
|
||||
// This is really a ShimRegistrarAggregate acting as a FlutterPlugin which is the
|
||||
// intermediate consumption side of the new plugin inside the shim.
|
||||
FlutterPlugin shimAggregateUnderTest = shimAggregateCaptor.getValue();
|
||||
// The FlutterPluginBinding is the supply side of the new plugin.
|
||||
shimAggregateUnderTest.onAttachedToEngine(mockFlutterPluginBinding);
|
||||
|
||||
// Consume something from the old plugin API.
|
||||
assertEquals(mockApplicationContext, registrarUnderTest.context());
|
||||
// Check that the value comes from the supply side of the new plugin.
|
||||
verify(mockFlutterPluginBinding).getApplicationContext();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
// Test is intentionally verifying deprecated behavior.
|
||||
@Test
|
||||
public void itSuppliesMultipleOldPlugins() {
|
||||
ShimPluginRegistry registryUnderTest = new ShimPluginRegistry(mockFlutterEngine);
|
||||
// Fully qualifed name because imports can not have deprecation supression.
|
||||
io.flutter.plugin.common.PluginRegistry.Registrar registrarUnderTest1 =
|
||||
registryUnderTest.registrarFor("test1");
|
||||
io.flutter.plugin.common.PluginRegistry.Registrar registrarUnderTest2 =
|
||||
registryUnderTest.registrarFor("test2");
|
||||
|
||||
ArgumentCaptor<FlutterPlugin> shimAggregateCaptor =
|
||||
ArgumentCaptor.forClass(FlutterPlugin.class);
|
||||
verify(mockPluginRegistry).add(shimAggregateCaptor.capture());
|
||||
// There's only one aggregate for many old plugins.
|
||||
FlutterPlugin shimAggregateUnderTest = shimAggregateCaptor.getValue();
|
||||
|
||||
// The FlutterPluginBinding is the supply side of the new plugin.
|
||||
shimAggregateUnderTest.onAttachedToEngine(mockFlutterPluginBinding);
|
||||
|
||||
// Since the 2 old plugins are supplied by the same intermediate FlutterPlugin, they should
|
||||
// get the same value.
|
||||
assertEquals(registrarUnderTest1.context(), registrarUnderTest2.context());
|
||||
verify(mockFlutterPluginBinding, times(2)).getApplicationContext();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
// Test is intentionally verifying deprecated behavior.
|
||||
@Test
|
||||
public void itCanOnlySupplyActivityBindingWhenUpstreamActivityIsAttached() {
|
||||
ShimPluginRegistry registryUnderTest = new ShimPluginRegistry(mockFlutterEngine);
|
||||
io.flutter.plugin.common.PluginRegistry.Registrar registrarUnderTest =
|
||||
registryUnderTest.registrarFor("test");
|
||||
|
||||
ArgumentCaptor<FlutterPlugin> shimAggregateCaptor =
|
||||
ArgumentCaptor.forClass(FlutterPlugin.class);
|
||||
verify(mockPluginRegistry).add(shimAggregateCaptor.capture());
|
||||
FlutterPlugin shimAggregateAsPlugin = shimAggregateCaptor.getValue();
|
||||
ActivityAware shimAggregateAsActivityAware = (ActivityAware) shimAggregateCaptor.getValue();
|
||||
|
||||
// Nothing is retrievable when nothing is attached.
|
||||
assertNull(registrarUnderTest.context());
|
||||
assertNull(registrarUnderTest.activity());
|
||||
|
||||
shimAggregateAsPlugin.onAttachedToEngine(mockFlutterPluginBinding);
|
||||
|
||||
assertEquals(mockApplicationContext, registrarUnderTest.context());
|
||||
assertNull(registrarUnderTest.activity());
|
||||
|
||||
shimAggregateAsActivityAware.onAttachedToActivity(mockActivityPluginBinding);
|
||||
|
||||
// Now context is the activity context.
|
||||
assertEquals(mockActivity, registrarUnderTest.activeContext());
|
||||
assertEquals(mockActivity, registrarUnderTest.activity());
|
||||
|
||||
shimAggregateAsActivityAware.onDetachedFromActivityForConfigChanges();
|
||||
|
||||
assertEquals(mockApplicationContext, registrarUnderTest.activeContext());
|
||||
assertNull(registrarUnderTest.activity());
|
||||
|
||||
shimAggregateAsActivityAware.onReattachedToActivityForConfigChanges(mockActivityPluginBinding);
|
||||
assertEquals(mockActivity, registrarUnderTest.activeContext());
|
||||
assertEquals(mockActivity, registrarUnderTest.activity());
|
||||
|
||||
shimAggregateAsActivityAware.onDetachedFromActivity();
|
||||
|
||||
assertEquals(mockApplicationContext, registrarUnderTest.activeContext());
|
||||
assertNull(registrarUnderTest.activity());
|
||||
|
||||
// Attach an activity again.
|
||||
shimAggregateAsActivityAware.onAttachedToActivity(mockActivityPluginBinding);
|
||||
|
||||
assertEquals(mockActivity, registrarUnderTest.activeContext());
|
||||
assertEquals(mockActivity, registrarUnderTest.activity());
|
||||
|
||||
// Now rip out the whole engine.
|
||||
shimAggregateAsPlugin.onDetachedFromEngine(mockFlutterPluginBinding);
|
||||
|
||||
// And everything should have been made unavailable.
|
||||
assertNull(registrarUnderTest.activeContext());
|
||||
assertNull(registrarUnderTest.activity());
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,6 @@
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application
|
||||
android:name="io.flutter.app.FlutterApplication"
|
||||
android:label="Scenarios App"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
|
||||
@ -66,7 +66,6 @@ def main():
|
||||
classpath.append(args.build_config_path)
|
||||
|
||||
packages = [
|
||||
'io.flutter.app',
|
||||
'io.flutter.embedding.android',
|
||||
'io.flutter.embedding.engine',
|
||||
'io.flutter.embedding.engine.dart',
|
||||
@ -78,7 +77,6 @@ def main():
|
||||
'io.flutter.embedding.engine.plugins.contentprovider',
|
||||
'io.flutter.embedding.engine.plugins.lifecycle',
|
||||
'io.flutter.embedding.engine.plugins.service',
|
||||
'io.flutter.embedding.engine.plugins.shim',
|
||||
'io.flutter.embedding.engine.renderer',
|
||||
'io.flutter.embedding.engine.systemchannels',
|
||||
'io.flutter.plugin.common',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user