[flutter roll] Revert "Determine lifecycle by looking at window focus also" (#41626)

Reverts flutter/engine#41094.

context: updated the java/android timeouts and details in b/280204906
diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart
index 329a054..6a63871 100644
--- a/lib/ui/platform_dispatcher.dart
+++ b/lib/ui/platform_dispatcher.dart
@@ -1642,61 +1642,31 @@
 /// States that an application can be in.
 ///
 /// The values below describe notifications from the operating system.
-/// Applications should not expect to always receive all possible notifications.
-/// For example, if the users pulls out the battery from the device, no
-/// notification will be sent before the application is suddenly terminated,
-/// along with the rest of the operating system.
-///
-/// For historical and name collision reasons, Flutter's application state names
-/// do not correspond one to one with the state names on all platforms. On
-/// Android, for instance, when the OS calls
-/// [`Activity.onPause`](https://developer.android.com/reference/android/app/Activity#onPause()),
-/// Flutter will enter the [inactive] state, but when Android calls
-/// [`Activity.onStop`](https://developer.android.com/reference/android/app/Activity#onStop()),
-/// Flutter enters the [paused] state. See the individual state's documentation
-/// for descriptions of what they mean on each platform.
+/// Applications should not expect to always receive all possible
+/// notifications. For example, if the users pulls out the battery from the
+/// device, no notification will be sent before the application is suddenly
+/// terminated, along with the rest of the operating system.
 ///
 /// See also:
 ///
-/// * [WidgetsBindingObserver], for a mechanism to observe the lifecycle state
-///   from the widgets layer.
-/// * iOS's [IOKit activity lifecycle](https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle?language=objc) documentation.
-/// * Android's [activity lifecycle](https://developer.android.com/guide/components/activities/activity-lifecycle) documentation.
-/// * macOS's [AppKit activity lifecycle](https://developer.apple.com/documentation/appkit/nsapplicationdelegate?language=objc) documentation.
+///  * [WidgetsBindingObserver], for a mechanism to observe the lifecycle state
+///    from the widgets layer.
 enum AppLifecycleState {
-  /// The application is visible and responsive to user input.
-  ///
-  /// On Android, this state corresponds to the Flutter host view having focus
-  /// ([`Activity.onWindowFocusChanged`](https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean))
-  /// was called with true) while in Android's "resumed" state. It is possible
-  /// for the Flutter app to be in the [inactive] state while still being in
-  /// Android's
-  /// ["onResume"](https://developer.android.com/guide/components/activities/activity-lifecycle)
-  /// state if the app has lost focus
-  /// ([`Activity.onWindowFocusChanged`](https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean))
-  /// was called with false), but hasn't had
-  /// [`Activity.onPause`](https://developer.android.com/reference/android/app/Activity#onPause())
-  /// called on it.
+  /// The application is visible and responding to user input.
   resumed,
 
   /// The application is in an inactive state and is not receiving user input.
   ///
   /// On iOS, this state corresponds to an app or the Flutter host view running
-  /// in the foreground inactive state. Apps transition to this state when in a
-  /// phone call, responding to a TouchID request, when entering the app
+  /// in the foreground inactive state. Apps transition to this state when in
+  /// a phone call, responding to a TouchID request, when entering the app
   /// switcher or the control center, or when the UIViewController hosting the
   /// Flutter app is transitioning.
   ///
-  /// On Android, this corresponds to an app or the Flutter host view running in
-  /// Android's paused state (i.e.
-  /// [`Activity.onPause`](https://developer.android.com/reference/android/app/Activity#onPause())
-  /// has been called), or in Android's "resumed" state (i.e.
-  /// [`Activity.onResume`](https://developer.android.com/reference/android/app/Activity#onResume())
-  /// has been called) but it has lost window focus. Examples of when apps
-  /// transition to this state include when the app is partially obscured or
-  /// another activity is focused, such as: a split-screen app, a phone call, a
-  /// picture-in-picture app, a system dialog, another view, when the
-  /// notification window shade is down, or the application switcher is visible.
+  /// On Android, this corresponds to an app or the Flutter host view running
+  /// in the foreground inactive state.  Apps transition to this state when
+  /// another activity is focused, such as a split-screen app, a phone call,
+  /// a picture-in-picture app, a system dialog, or another view.
   ///
   /// Apps in this state should assume that they may be [paused] at any time.
   inactive,
diff --git a/shell/platform/android/io/flutter/app/FlutterActivity.java b/shell/platform/android/io/flutter/app/FlutterActivity.java
index 932ad2c..a28176b 100644
--- a/shell/platform/android/io/flutter/app/FlutterActivity.java
+++ b/shell/platform/android/io/flutter/app/FlutterActivity.java
@@ -158,12 +158,6 @@
   }
 
   @Override
-  public void onWindowFocusChanged(boolean hasFocus) {
-    super.onWindowFocusChanged(hasFocus);
-    eventDelegate.onWindowFocusChanged(hasFocus);
-  }
-
-  @Override
   public void onTrimMemory(int level) {
     eventDelegate.onTrimMemory(level);
   }
diff --git a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
index bcc54b1..9883d6e 100644
--- a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
+++ b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
@@ -261,11 +261,6 @@
   }
 
   @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.
diff --git a/shell/platform/android/io/flutter/app/FlutterActivityEvents.java b/shell/platform/android/io/flutter/app/FlutterActivityEvents.java
index abbdec4..9340adb 100644
--- a/shell/platform/android/io/flutter/app/FlutterActivityEvents.java
+++ b/shell/platform/android/io/flutter/app/FlutterActivityEvents.java
@@ -64,10 +64,4 @@
 
   /** @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);
 }
diff --git a/shell/platform/android/io/flutter/app/FlutterFragmentActivity.java b/shell/platform/android/io/flutter/app/FlutterFragmentActivity.java
index c31a5a2..bf8935e 100644
--- a/shell/platform/android/io/flutter/app/FlutterFragmentActivity.java
+++ b/shell/platform/android/io/flutter/app/FlutterFragmentActivity.java
@@ -156,12 +156,6 @@
   }
 
   @Override
-  public void onWindowFocusChanged(boolean hasFocus) {
-    super.onWindowFocusChanged(hasFocus);
-    eventDelegate.onWindowFocusChanged(hasFocus);
-  }
-
-  @Override
   public void onTrimMemory(int level) {
     super.onTrimMemory(level);
     eventDelegate.onTrimMemory(level);
diff --git a/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java b/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java
index 887a911..023e723 100644
--- a/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java
+++ b/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java
@@ -28,7 +28,6 @@
         PluginRegistry.RequestPermissionsResultListener,
         PluginRegistry.ActivityResultListener,
         PluginRegistry.NewIntentListener,
-        PluginRegistry.WindowFocusChangedListener,
         PluginRegistry.UserLeaveHintListener,
         PluginRegistry.ViewDestroyListener {
   private static final String TAG = "FlutterPluginRegistry";
@@ -45,7 +44,6 @@
   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) {
@@ -185,12 +183,6 @@
     }
 
     @Override
-    public Registrar addWindowFocusChangedListener(WindowFocusChangedListener listener) {
-      mWindowFocusChangedListeners.add(listener);
-      return this;
-    }
-
-    @Override
     public Registrar addViewDestroyListener(ViewDestroyListener listener) {
       mViewDestroyListeners.add(listener);
       return this;
@@ -236,13 +228,6 @@
   }
 
   @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) {
diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java
index 53344a1..ef8b87d 100644
--- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java
+++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java
@@ -950,14 +950,6 @@
   }
 
   @Override
-  public void onWindowFocusChanged(boolean hasFocus) {
-    super.onWindowFocusChanged(hasFocus);
-    if (stillAttachedForEvent("onWindowFocusChanged")) {
-      delegate.onWindowFocusChanged(hasFocus);
-    }
-  }
-
-  @Override
   public void onTrimMemory(int level) {
     super.onTrimMemory(level);
     if (stillAttachedForEvent("onTrimMemory")) {
diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java
index 359eca9..9a9f4d9 100644
--- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java
+++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java
@@ -581,7 +581,7 @@
   void onResume() {
     Log.v(TAG, "onResume()");
     ensureAlive();
-    if (host.shouldDispatchAppLifecycleState() && flutterEngine != null) {
+    if (host.shouldDispatchAppLifecycleState()) {
       flutterEngine.getLifecycleChannel().appIsResumed();
     }
   }
@@ -629,7 +629,7 @@
   void onPause() {
     Log.v(TAG, "onPause()");
     ensureAlive();
-    if (host.shouldDispatchAppLifecycleState() && flutterEngine != null) {
+    if (host.shouldDispatchAppLifecycleState()) {
       flutterEngine.getLifecycleChannel().appIsInactive();
     }
   }
@@ -652,7 +652,7 @@
     Log.v(TAG, "onStop()");
     ensureAlive();
 
-    if (host.shouldDispatchAppLifecycleState() && flutterEngine != null) {
+    if (host.shouldDispatchAppLifecycleState()) {
       flutterEngine.getLifecycleChannel().appIsPaused();
     }
 
@@ -763,7 +763,7 @@
       platformPlugin = null;
     }
 
-    if (host.shouldDispatchAppLifecycleState() && flutterEngine != null) {
+    if (host.shouldDispatchAppLifecycleState()) {
       flutterEngine.getLifecycleChannel().appIsDetached();
     }
 
@@ -899,27 +899,6 @@
   }
 
   /**
-   * Invoke this from {@code Activity#onWindowFocusChanged()}.
-   *
-   * <p>A {@code Fragment} host must have its containing {@code Activity} forward this call so that
-   * the {@code Fragment} can then invoke this method.
-   */
-  void onWindowFocusChanged(boolean hasFocus) {
-    ensureAlive();
-    Log.v(TAG, "Received onWindowFocusChanged: " + (hasFocus ? "true" : "false"));
-    if (host.shouldDispatchAppLifecycleState() && flutterEngine != null) {
-      // TODO(gspencergoog): Once we have support for multiple windows/views,
-      // this code will need to consult the list of windows/views to determine if
-      // any windows in the app are focused and call the appropriate function.
-      if (hasFocus) {
-        flutterEngine.getLifecycleChannel().aWindowIsFocused();
-      } else {
-        flutterEngine.getLifecycleChannel().noWindowsAreFocused();
-      }
-    }
-  }
-
-  /**
    * Invoke this from {@link android.app.Activity#onTrimMemory(int)}.
    *
    * <p>A {@code Fragment} host must have its containing {@code Activity} forward this call so that
diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java
index 85ce3ad..0ef5d87 100644
--- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java
+++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java
@@ -8,16 +8,13 @@
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnWindowFocusChangeListener;
 import androidx.activity.OnBackPressedCallback;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentActivity;
@@ -170,19 +167,6 @@
   protected static final String ARG_SHOULD_AUTOMATICALLY_HANDLE_ON_BACK_PRESSED =
       "should_automatically_handle_on_back_pressed";
 
-  @RequiresApi(18)
-  private final OnWindowFocusChangeListener onWindowFocusChangeListener =
-      Build.VERSION.SDK_INT >= 18
-          ? new OnWindowFocusChangeListener() {
-            @Override
-            public void onWindowFocusChanged(boolean hasFocus) {
-              if (stillAttachedForEvent("onWindowFocusChanged")) {
-                delegate.onWindowFocusChanged(hasFocus);
-              }
-            }
-          }
-          : null;
-
   /**
    * Creates a {@code FlutterFragment} with a default configuration.
    *
@@ -1126,22 +1110,8 @@
   }
 
   @Override
-  public void onViewCreated(View view, Bundle savedInstanceState) {
-    super.onViewCreated(view, savedInstanceState);
-    if (Build.VERSION.SDK_INT >= 18) {
-      view.getViewTreeObserver().addOnWindowFocusChangeListener(onWindowFocusChangeListener);
-    }
-  }
-
-  @Override
   public void onDestroyView() {
     super.onDestroyView();
-    if (Build.VERSION.SDK_INT >= 18) {
-      // onWindowFocusChangeListener is API 18+ only.
-      requireView()
-          .getViewTreeObserver()
-          .removeOnWindowFocusChangeListener(onWindowFocusChangeListener);
-    }
     if (stillAttachedForEvent("onDestroyView")) {
       delegate.onDestroyView();
     }
diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java
index e1ae744..e2bc8b5 100644
--- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java
+++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java
@@ -733,10 +733,6 @@
         onUserLeaveHintListeners = new HashSet<>();
 
     @NonNull
-    private final Set<io.flutter.plugin.common.PluginRegistry.WindowFocusChangedListener>
-        onWindowFocusChangedListeners = new HashSet<>();
-
-    @NonNull
     private final Set<OnSaveInstanceStateListener> onSaveInstanceStateListeners = new HashSet<>();
 
     public FlutterEngineActivityPluginBinding(
@@ -852,25 +848,6 @@
     }
 
     @Override
-    public void addOnWindowFocusChangedListener(
-        @NonNull io.flutter.plugin.common.PluginRegistry.WindowFocusChangedListener listener) {
-      onWindowFocusChangedListeners.add(listener);
-    }
-
-    @Override
-    public void removeOnWindowFocusChangedListener(
-        @NonNull io.flutter.plugin.common.PluginRegistry.WindowFocusChangedListener listener) {
-      onWindowFocusChangedListeners.remove(listener);
-    }
-
-    void onWindowFocusChanged(boolean hasFocus) {
-      for (io.flutter.plugin.common.PluginRegistry.WindowFocusChangedListener listener :
-          onWindowFocusChangedListeners) {
-        listener.onWindowFocusChanged(hasFocus);
-      }
-    }
-
-    @Override
     public void addOnSaveStateListener(@NonNull OnSaveInstanceStateListener listener) {
       onSaveInstanceStateListeners.add(listener);
     }
diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityPluginBinding.java b/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityPluginBinding.java
index 8c5f84b..fc2deca 100644
--- a/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityPluginBinding.java
+++ b/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityPluginBinding.java
@@ -92,19 +92,6 @@
   void removeOnUserLeaveHintListener(@NonNull PluginRegistry.UserLeaveHintListener listener);
 
   /**
-   * Adds a listener that is invoked whenever the associated {@link android.app.Activity}'s {@code
-   * onWindowFocusChanged()} method is invoked.
-   */
-  void addOnWindowFocusChangedListener(@NonNull PluginRegistry.WindowFocusChangedListener listener);
-
-  /**
-   * Removes a listener that was added in {@link
-   * #addOnWindowFocusChangedListener(PluginRegistry.WindowFocusChangedListener)}.
-   */
-  void removeOnWindowFocusChangedListener(
-      @NonNull PluginRegistry.WindowFocusChangedListener listener);
-
-  /**
    * Adds a listener that is invoked when the associated {@code Activity} or {@code Fragment} saves
    * and restores instance state.
    */
diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java b/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java
index d27da01..9c40d0a 100644
--- a/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java
+++ b/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java
@@ -39,8 +39,6 @@
       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;
 
@@ -149,18 +147,6 @@
   }
 
   @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) {
@@ -227,8 +213,5 @@
     for (PluginRegistry.UserLeaveHintListener listener : userLeaveHintListeners) {
       activityPluginBinding.addOnUserLeaveHintListener(listener);
     }
-    for (PluginRegistry.WindowFocusChangedListener listener : WindowFocusChangedListeners) {
-      activityPluginBinding.addOnWindowFocusChangedListener(listener);
-    }
   }
 }
diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java
index f34f774..9e8c22b 100644
--- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java
+++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java
@@ -5,106 +5,39 @@
 package io.flutter.embedding.engine.systemchannels;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
 import io.flutter.Log;
 import io.flutter.embedding.engine.dart.DartExecutor;
 import io.flutter.plugin.common.BasicMessageChannel;
 import io.flutter.plugin.common.StringCodec;
 
-/**
- * A {@link BasicMessageChannel} that communicates lifecycle events to the framework.
- *
- * <p>The activity listens to the Android lifecycle events, in addition to the focus events for
- * windows, and this channel combines that information to decide if the application is the inactive,
- * resumed, paused, or detached state.
- */
+/** TODO(mattcarroll): fill in javadoc for LifecycleChannel. */
 public class LifecycleChannel {
   private static final String TAG = "LifecycleChannel";
-  private static final String CHANNEL_NAME = "flutter/lifecycle";
 
-  // These should stay in sync with the AppLifecycleState enum in the framework.
-  private static final String RESUMED = "AppLifecycleState.resumed";
-  private static final String INACTIVE = "AppLifecycleState.inactive";
-  private static final String PAUSED = "AppLifecycleState.paused";
-  private static final String DETACHED = "AppLifecycleState.detached";
-
-  private String lastAndroidState = "";
-  private String lastFlutterState = "";
-  private boolean lastFocus = false;
-
-  @NonNull private final BasicMessageChannel<String> channel;
+  @NonNull public final BasicMessageChannel<String> channel;
 
   public LifecycleChannel(@NonNull DartExecutor dartExecutor) {
-    this(new BasicMessageChannel<String>(dartExecutor, CHANNEL_NAME, StringCodec.INSTANCE));
-  }
-
-  @VisibleForTesting
-  public LifecycleChannel(@NonNull BasicMessageChannel<String> channel) {
-    this.channel = channel;
-  }
-
-  // Here's the state table this implements:
-  //
-  // | Android State | Window focused | Flutter state |
-  // |---------------|----------------|---------------|
-  // | Resumed       |     true       |    resumed    |
-  // | Resumed       |     false      |    inactive   |
-  // | Paused        |     true       |    inactive   |
-  // | Paused        |     false      |    inactive   |
-  // | Stopped       |     true       |    paused     |
-  // | Stopped       |     false      |    paused     |
-  // | Detached      |     true       |    detached   |
-  // | Detached      |     false      |    detached   |
-  private void sendState(String state, boolean hasFocus) {
-    if (lastAndroidState == state && hasFocus == lastFocus) {
-      // No inputs changed, so Flutter state could not have changed.
-      return;
-    }
-    String newState;
-    if (state == RESUMED) {
-      // Focus is only taken into account when the Android state is "Resumed".
-      // In all other states, focus is ignored, because we can't know what order
-      // Android lifecycle notifications and window focus notifications events
-      // will arrive in, and those states don't send input events anyhow.
-      newState = hasFocus ? RESUMED : INACTIVE;
-    } else {
-      newState = state;
-    }
-    // Keep the last reported values for future updates.
-    lastAndroidState = state;
-    lastFocus = hasFocus;
-    if (newState == lastFlutterState) {
-      // No change in the resulting Flutter state, so don't report anything.
-      return;
-    }
-    Log.v(TAG, "Sending " + newState + " message.");
-    channel.send(newState);
-    lastFlutterState = newState;
-  }
-
-  // Called if at least one window in the app has focus.
-  public void aWindowIsFocused() {
-    sendState(lastAndroidState, true);
-  }
-
-  // Called if no windows in the app have focus.
-  public void noWindowsAreFocused() {
-    sendState(lastAndroidState, false);
-  }
-
-  public void appIsResumed() {
-    sendState(RESUMED, lastFocus);
+    this.channel =
+        new BasicMessageChannel<>(dartExecutor, "flutter/lifecycle", StringCodec.INSTANCE);
   }
 
   public void appIsInactive() {
-    sendState(INACTIVE, lastFocus);
+    Log.v(TAG, "Sending AppLifecycleState.inactive message.");
+    channel.send("AppLifecycleState.inactive");
+  }
+
+  public void appIsResumed() {
+    Log.v(TAG, "Sending AppLifecycleState.resumed message.");
+    channel.send("AppLifecycleState.resumed");
   }
 
   public void appIsPaused() {
-    sendState(PAUSED, lastFocus);
+    Log.v(TAG, "Sending AppLifecycleState.paused message.");
+    channel.send("AppLifecycleState.paused");
   }
 
   public void appIsDetached() {
-    sendState(DETACHED, lastFocus);
+    Log.v(TAG, "Sending AppLifecycleState.detached message.");
+    channel.send("AppLifecycleState.detached");
   }
 }
diff --git a/shell/platform/android/io/flutter/plugin/common/PluginRegistry.java b/shell/platform/android/io/flutter/plugin/common/PluginRegistry.java
index 4859617..649bce8 100644
--- a/shell/platform/android/io/flutter/plugin/common/PluginRegistry.java
+++ b/shell/platform/android/io/flutter/plugin/common/PluginRegistry.java
@@ -311,23 +311,6 @@
 
     /**
      * 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
@@ -406,14 +389,6 @@
   }
 
   /**
-   * Delegate interface for handling window focus changes on behalf of the main {@link
-   * android.app.Activity}.
-   */
-  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.
diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java
index d5daa43..8c1f545 100644
--- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java
+++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java
@@ -107,36 +107,13 @@
     // By the time an Activity/Fragment is started, we don't expect any lifecycle messages
     // to have been sent to Flutter.
     delegate.onStart();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).aWindowIsFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).noWindowsAreFocused();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsResumed();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsInactive();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsPaused();
+    verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsInactive();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsDetached();
 
     // When the Activity/Fragment is resumed, a resumed message should have been sent to Flutter.
     delegate.onResume();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).aWindowIsFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).noWindowsAreFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsResumed();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsInactive();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsPaused();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsDetached();
-
-    // When the app loses focus because something else has it (e.g. notification
-    // windowshade or app switcher), it should go to inactive.
-    delegate.onWindowFocusChanged(false);
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).aWindowIsFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).noWindowsAreFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsResumed();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsInactive();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsPaused();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsDetached();
-
-    // When the app regains focus, it should go to resumed again.
-    delegate.onWindowFocusChanged(true);
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).aWindowIsFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).noWindowsAreFocused();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsResumed();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsInactive();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsPaused();
@@ -144,8 +121,6 @@
 
     // When the Activity/Fragment is paused, an inactive message should have been sent to Flutter.
     delegate.onPause();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).aWindowIsFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).noWindowsAreFocused();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsResumed();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsInactive();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsPaused();
@@ -155,8 +130,6 @@
     // Notice that Flutter uses the term "paused" in a different way, and at a different time
     // than the Android OS.
     delegate.onStop();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).aWindowIsFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).noWindowsAreFocused();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsResumed();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsInactive();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsPaused();
@@ -164,8 +137,6 @@
 
     // When activity detaches, a detached message should have been sent to Flutter.
     delegate.onDetach();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).aWindowIsFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), times(1)).noWindowsAreFocused();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsResumed();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsInactive();
     verify(mockFlutterEngine.getLifecycleChannel(), times(1)).appIsPaused();
@@ -186,14 +157,10 @@
     delegate.onCreateView(null, null, null, 0, true);
     delegate.onStart();
     delegate.onResume();
-    delegate.onWindowFocusChanged(false);
-    delegate.onWindowFocusChanged(true);
     delegate.onPause();
     delegate.onStop();
     delegate.onDetach();
 
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).aWindowIsFocused();
-    verify(mockFlutterEngine.getLifecycleChannel(), never()).noWindowsAreFocused();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsResumed();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsPaused();
     verify(mockFlutterEngine.getLifecycleChannel(), never()).appIsInactive();
diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/LifecycleChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/LifecycleChannelTest.java
deleted file mode 100644
index e9211d5..0000000
--- a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/LifecycleChannelTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package io.flutter.embedding.engine.systemchannels;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import io.flutter.plugin.common.BasicMessageChannel;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.robolectric.annotation.Config;
-
-@Config(manifest = Config.NONE)
-@RunWith(AndroidJUnit4.class)
-public class LifecycleChannelTest {
-  LifecycleChannel lifecycleChannel;
-  BasicMessageChannel<String> mockChannel;
-
-  @Before
-  public void setUp() {
-    mockChannel = mock(BasicMessageChannel.class);
-    lifecycleChannel = new LifecycleChannel(mockChannel);
-  }
-
-  @Test
-  public void lifecycleChannel_handlesResumed() {
-    lifecycleChannel.appIsResumed();
-    ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(1)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.inactive", stringArgumentCaptor.getValue());
-
-    lifecycleChannel.aWindowIsFocused();
-    stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(2)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.resumed", stringArgumentCaptor.getValue());
-
-    lifecycleChannel.noWindowsAreFocused();
-    stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(3)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.inactive", stringArgumentCaptor.getValue());
-
-    // Stays inactive, so no event is sent.
-    lifecycleChannel.appIsInactive();
-    verify(mockChannel, times(3)).send(any(String.class));
-
-    // Stays inactive, so no event is sent.
-    lifecycleChannel.appIsResumed();
-    verify(mockChannel, times(3)).send(any(String.class));
-
-    lifecycleChannel.aWindowIsFocused();
-    stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(4)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.resumed", stringArgumentCaptor.getValue());
-  }
-
-  @Test
-  public void lifecycleChannel_handlesInactive() {
-    lifecycleChannel.appIsInactive();
-    ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(1)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.inactive", stringArgumentCaptor.getValue());
-
-    // Stays inactive, so no event is sent.
-    lifecycleChannel.aWindowIsFocused();
-    verify(mockChannel, times(1)).send(any(String.class));
-
-    // Stays inactive, so no event is sent.
-    lifecycleChannel.noWindowsAreFocused();
-    verify(mockChannel, times(1)).send(any(String.class));
-
-    lifecycleChannel.appIsResumed();
-    lifecycleChannel.aWindowIsFocused();
-    stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(2)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.resumed", stringArgumentCaptor.getValue());
-  }
-
-  @Test
-  public void lifecycleChannel_handlesPaused() {
-    // Stays inactive, so no event is sent.
-    lifecycleChannel.appIsPaused();
-    ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(1)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.paused", stringArgumentCaptor.getValue());
-
-    // Stays paused, so no event is sent.
-    lifecycleChannel.aWindowIsFocused();
-    verify(mockChannel, times(1)).send(any(String.class));
-
-    lifecycleChannel.noWindowsAreFocused();
-    verify(mockChannel, times(1)).send(any(String.class));
-
-    lifecycleChannel.appIsResumed();
-    stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(2)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.inactive", stringArgumentCaptor.getValue());
-
-    lifecycleChannel.aWindowIsFocused();
-    stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(3)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.resumed", stringArgumentCaptor.getValue());
-  }
-
-  @Test
-  public void lifecycleChannel_handlesDetached() {
-    // Stays inactive, so no event is sent.
-    lifecycleChannel.appIsDetached();
-    ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(1)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.detached", stringArgumentCaptor.getValue());
-
-    // Stays paused, so no event is sent.
-    lifecycleChannel.aWindowIsFocused();
-    verify(mockChannel, times(1)).send(any(String.class));
-
-    lifecycleChannel.noWindowsAreFocused();
-    verify(mockChannel, times(1)).send(any(String.class));
-
-    lifecycleChannel.appIsResumed();
-    stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(2)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.inactive", stringArgumentCaptor.getValue());
-
-    lifecycleChannel.aWindowIsFocused();
-    stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-    verify(mockChannel, times(3)).send(stringArgumentCaptor.capture());
-    assertEquals("AppLifecycleState.resumed", stringArgumentCaptor.getValue());
-  }
-}