Introduce KeyboardStateManager to maintain keyboardstate as show or hide.

- Add a feature flag for IME Latency logging.

- Removed mShowImeAfterFirstLayout from ExtendedEditText.

   http://ag/1414509 added `mShowImeAfterFirstLayout`and cl description
   says "Show IME when search query != null after rotation".

   I verified the behavior by turning on "Allow home screen rotation".
   Keyboard is not getting dismissed on rotation in AA+ screen in a-z list
   or even in the search screen.
   Video : https://drive.google.com/file/d/1BWUTrW9OSEo6ojErj8INMwjFCPArVD4B/view?usp=sharing&resourcekey=0-SXTcKyUw1wCSi8Bm37ktow

Bug: 240192346
Test: Manual.

Verified by setting `ENABLE_KEYBOARD_TRANSITION_SYNC` to false and for
following usecases.

- All apps entry with ime enabled, scrolling a-z list to hide keyboard
- Folder name change - showing and dismissing keyboard
- Toast entry from Allapps and QSB - showing and dismissing keyboard

Change-Id: I1a6b5759b8e71e77744f58677b6d1b73e2f633e8
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 4629ca7..98c71c5 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3;
 
+import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.SHOW;
 import static com.android.launcher3.util.UiThreadHelper.hideKeyboardAsync;
 
 import android.content.Context;
@@ -33,8 +34,6 @@
  * Note: AppCompatEditText doesn't fully support #displayCompletions and #onCommitCompletion
  */
 public class ExtendedEditText extends EditText {
-
-    private boolean mShowImeAfterFirstLayout;
     private boolean mForceDisableSuggestions = false;
 
     /**
@@ -85,21 +84,9 @@
         return false;
     }
 
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        if (mShowImeAfterFirstLayout) {
-            // soft input only shows one frame after the layout of the EditText happens,
-            post(() -> {
-                showSoftInput();
-                mShowImeAfterFirstLayout = false;
-            });
-        }
-    }
-
-
     public void showKeyboard() {
-        mShowImeAfterFirstLayout = !showSoftInput();
+        onKeyboardShown();
+        showSoftInput();
     }
 
     public void hideKeyboard() {
@@ -107,6 +94,11 @@
         clearFocus();
     }
 
+    protected void onKeyboardShown() {
+        ActivityContext.lookupContext(getContext()).getStatsLogManager()
+                .keyboardStateManager().setKeyboardState(SHOW);
+    }
+
     private boolean showSoftInput() {
         return requestFocus() &&
                 getContext().getSystemService(InputMethodManager.class)
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 329a24c..e979a65 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -288,6 +288,11 @@
     public static final BooleanFlag SHOW_SEARCH_EDUCARD_QSB = new DeviceFlag(
             "SHOW_SEARCH_EDUCARD_QSB", false, "Shows Search Educard for QSB entry in OneSearch.");
 
+    public static final BooleanFlag ENABLE_IME_LATENCY_LOGGER = getDebugFlag(
+            "ENABLE_IME_LATENCY_LOGGER", false,
+            "Enable option to log the keyboard latency for both atomic and controlled keyboard "
+                    + "animations on an EditText");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/logging/KeyboardStateManager.java b/src/com/android/launcher3/logging/KeyboardStateManager.java
new file mode 100644
index 0000000..3103af1
--- /dev/null
+++ b/src/com/android/launcher3/logging/KeyboardStateManager.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.logging;
+
+import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.NO_IME_ACTION;
+
+import android.os.SystemClock;
+
+/**
+ * Class to maintain keyboard states.
+ */
+public class KeyboardStateManager {
+    private long mUpdatedTime;
+
+    public enum KeyboardState {
+        NO_IME_ACTION,
+        SHOW,
+        HIDE,
+    }
+
+    private KeyboardState mKeyboardState;
+
+    public KeyboardStateManager() {
+        mKeyboardState = NO_IME_ACTION;
+    }
+
+    /**
+     * Returns time when keyboard state was updated.
+     */
+    public long getLastUpdatedTime() {
+        return mUpdatedTime;
+    }
+
+    /**
+     * Returns current keyboard state.
+     */
+    public KeyboardState getKeyboardState() {
+        return mKeyboardState;
+    }
+
+    /**
+     * Setter method to set keyboard state.
+     */
+    public void setKeyboardState(KeyboardState keyboardState) {
+        mUpdatedTime = SystemClock.elapsedRealtime();
+        mKeyboardState = keyboardState;
+    }
+}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index c4ec4e3..651372f 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -56,6 +56,7 @@
     private InstanceId mInstanceId;
 
     protected @Nullable ActivityContext mActivityContext = null;
+    private KeyboardStateManager mKeyboardStateManager;
 
     /**
      * Returns event enum based on the two state transition information when swipe
@@ -816,6 +817,16 @@
         return logger;
     }
 
+    /**
+     * Returns a singleton KeyboardStateManager.
+     */
+    public KeyboardStateManager keyboardStateManager() {
+        if (mKeyboardStateManager == null) {
+            mKeyboardStateManager = new KeyboardStateManager();
+        }
+        return mKeyboardStateManager;
+    }
+
     protected StatsLogger createLogger() {
         return new StatsLogger() {
         };
diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index 6bc26e7..1cb0752 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -40,4 +40,9 @@
      * When turned on, we enable suggest related logging.
      */
     public static final String SEARCH_LOGGING = "SearchLogging";
+
+    /**
+     * When turned on, we enable IME related latency related logging.
+     */
+    public static final String IME_LATENCY_LOGGING = "ImeLatencyLogging";
 }
diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java
index 7e6711f..b952090 100644
--- a/src/com/android/launcher3/util/UiThreadHelper.java
+++ b/src/com/android/launcher3/util/UiThreadHelper.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.util;
 
+import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
@@ -25,7 +26,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
-import android.util.Log;
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowInsetsController;
@@ -64,6 +64,7 @@
             WindowInsets insets = root.getRootWindowInsets();
             boolean isImeShown = insets != null && insets.isVisible(WindowInsets.Type.ime());
             if (wic != null && isImeShown) {
+                activityContext.getStatsLogManager().keyboardStateManager().setKeyboardState(HIDE);
                 // this method cannot be called cross threads
                 wic.hide(WindowInsets.Type.ime());
                 activityContext.getStatsLogManager().logger()