[PK Setting] add keyboard review under keyboard selection page

Demo video as attached in bug.
Add new image view for keyboard layout review.
Reuse NewKeyboardLayoutPickerController under
NewKeyboardLayoutPickerFragment when get update for keyboard layout, get
preview image from inputManager and set to the view.

This feature will be guided with keyboard_layout_preview_flag, if the
flag is off, preview image from InputManager will be null.

Bug: 305588594
Test: Verified on device
Change-Id: Ic6f8e469d3cf7114dab6935304706ad42bf83608
diff --git a/res/layout/keyboard_layout_picker.xml b/res/layout/keyboard_layout_picker.xml
index 6b163da..b25c228 100644
--- a/res/layout/keyboard_layout_picker.xml
+++ b/res/layout/keyboard_layout_picker.xml
@@ -20,6 +20,13 @@
     android:id="@+id/keyboard_layout_picker_container"
     android:orientation="vertical">
 
+    <ImageView
+        android:id="@+id/keyboard_layout_preview"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:adjustViewBounds="true"
+        android:scaleType="fitCenter"/>
+
     <FrameLayout
         android:id="@+id/keyboard_layout_title"
         android:layout_width="match_parent"
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index d7a276e..66397c0 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -479,7 +479,10 @@
                 mDialogFragment.dismiss();
                 mDialogFragment = null;
             }
-            getListView().clearOnScrollListeners();
+            RecyclerView view = getListView();
+            if (view != null) {
+                view.clearOnScrollListeners();
+            }
         }
         super.onDetach();
     }
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
index 11740ec..e934964 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
@@ -27,6 +27,20 @@
 public class NewKeyboardLayoutPickerContent extends DashboardFragment {
 
     private static final String TAG = "KeyboardLayoutPicker";
+    private NewKeyboardLayoutPickerController mNewKeyboardLayoutPickerController;
+    private ControllerUpdateCallback mControllerUpdateCallback;
+
+    public interface ControllerUpdateCallback {
+        /**
+         * Called when mNewKeyBoardLayoutPickerController been initialized.
+         */
+        void onControllerUpdated(NewKeyboardLayoutPickerController
+                newKeyboardLayoutPickerController);
+    }
+
+    public void setControllerUpdateCallback(ControllerUpdateCallback controllerUpdateCallback) {
+        this.mControllerUpdateCallback = controllerUpdateCallback;
+    }
 
     @Override
     public void onAttach(Context context) {
@@ -40,7 +54,11 @@
             getActivity().finish();
             return;
         }
-        use(NewKeyboardLayoutPickerController.class).initialize(this);
+        mNewKeyboardLayoutPickerController = use(NewKeyboardLayoutPickerController.class);
+        mNewKeyboardLayoutPickerController.initialize(this);
+        if (mControllerUpdateCallback != null) {
+            mControllerUpdateCallback.onControllerUpdated(mNewKeyboardLayoutPickerController);
+        }
     }
 
     @Override
@@ -56,4 +74,8 @@
     protected int getPreferenceScreenResId() {
         return R.xml.new_keyboard_layout_picker_fragment;
     }
+
+    public NewKeyboardLayoutPickerController getController() {
+        return mNewKeyboardLayoutPickerController;
+    }
 }
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
index 9545276..ac8037f 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
@@ -59,6 +59,7 @@
     private String mFinalSelectedLayout;
     private String mLayout;
     private MetricsFeatureProvider mMetricsFeatureProvider;
+    private KeyboardLayoutSelectedCallback mKeyboardLayoutSelectedCallback;
 
     public NewKeyboardLayoutPickerController(Context context, String key) {
         super(context, key);
@@ -100,7 +101,7 @@
 
     @Override
     public void onStop() {
-        if (!mLayout.equals(mFinalSelectedLayout)) {
+        if (mLayout != null && !mLayout.equals(mFinalSelectedLayout)) {
             String change = "From:" + mLayout + ", to:" + mFinalSelectedLayout;
             mMetricsFeatureProvider.action(
                     mContext, SettingsEnums.ACTION_PK_LAYOUT_CHANGED, change);
@@ -121,6 +122,14 @@
         return AVAILABLE;
     }
 
+    /**
+     * Registers {@link KeyboardLayoutSelectedCallback} and get updated.
+     */
+    public void registerKeyboardSelectedCallback(KeyboardLayoutSelectedCallback
+            keyboardLayoutSelectedCallback) {
+        this.mKeyboardLayoutSelectedCallback = keyboardLayoutSelectedCallback;
+    }
+
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
         if (!(preference instanceof TickButtonPreference)) {
@@ -128,6 +137,9 @@
         }
 
         final TickButtonPreference pref = (TickButtonPreference) preference;
+        if (mKeyboardLayoutSelectedCallback != null && mPreferenceMap.containsKey(preference)) {
+            mKeyboardLayoutSelectedCallback.onSelected(mPreferenceMap.get(preference));
+        }
         pref.setSelected(true);
         if (mPreviousSelection != null && !mPreviousSelection.equals(preference.getKey())) {
             TickButtonPreference preSelectedPref = mScreen.findPreference(mPreviousSelection);
@@ -166,6 +178,9 @@
             pref.setTitle(layout.getLabel());
 
             if (mLayout.equals(layout.getLabel())) {
+                if (mKeyboardLayoutSelectedCallback != null) {
+                    mKeyboardLayoutSelectedCallback.onSelected(layout);
+                }
                 pref.setSelected(true);
                 mPreviousSelection = layout.getDescriptor();
             }
@@ -200,4 +215,11 @@
         }
         return label;
     }
+
+    public interface KeyboardLayoutSelectedCallback {
+        /**
+         * Called when KeyboardLayout been selected.
+         */
+        void onSelected(KeyboardLayout keyboardLayout);
+    }
 }
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
index 88cacd2..f583971 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
@@ -16,35 +16,75 @@
 
 package com.android.settings.inputmethod;
 
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import android.graphics.drawable.Drawable;
+import android.hardware.input.InputManager;
+import android.hardware.input.KeyboardLayout;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.ImageView;
 
 import androidx.fragment.app.Fragment;
 
 import com.android.settings.R;
 
+//TODO: b/316243168 - [Physical Keyboard Setting] Refactor NewKeyboardLayoutPickerFragment
 public class NewKeyboardLayoutPickerFragment extends Fragment {
+    private static final int DEFAULT_KEYBOARD_PREVIEW_WIDTH = 1630;
+    private static final int DEFAULT_KEYBOARD_PREVIEW_HEIGHT = 540;
+
+    private ImageView mKeyboardLayoutPreview;
+    private InputManager mInputManager;
+    private final NewKeyboardLayoutPickerController.KeyboardLayoutSelectedCallback
+            mKeyboardLayoutSelectedCallback =
+            new NewKeyboardLayoutPickerController.KeyboardLayoutSelectedCallback() {
+                @Override
+                public void onSelected(KeyboardLayout keyboardLayout) {
+                    if (mInputManager != null && mKeyboardLayoutPreview != null) {
+                        Drawable previewDrawable = mInputManager.getKeyboardLayoutPreview(
+                                keyboardLayout,
+                                DEFAULT_KEYBOARD_PREVIEW_WIDTH, DEFAULT_KEYBOARD_PREVIEW_HEIGHT);
+                        mKeyboardLayoutPreview.setVisibility(
+                                previewDrawable == null ? GONE : VISIBLE);
+                        if (previewDrawable != null) {
+                            mKeyboardLayoutPreview.setImageDrawable(previewDrawable);
+                        }
+                    }
+                }
+            };
+
+    private final NewKeyboardLayoutPickerContent.ControllerUpdateCallback
+            mControllerUpdateCallback =
+                    newKeyboardLayoutPickerController -> {
+                        if (newKeyboardLayoutPickerController != null) {
+                            newKeyboardLayoutPickerController.registerKeyboardSelectedCallback(
+                                    mKeyboardLayoutSelectedCallback);
+                        }
+                    };
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-
+        mInputManager = requireContext().getSystemService(InputManager.class);
         ViewGroup fragmentView = (ViewGroup) inflater.inflate(
                 R.layout.keyboard_layout_picker, container, false);
+        mKeyboardLayoutPreview = fragmentView.findViewById(R.id.keyboard_layout_preview);
         getActivity().getSupportFragmentManager()
                 .beginTransaction()
                 .replace(R.id.keyboard_layout_title, new NewKeyboardLayoutPickerTitle())
                 .commit();
 
         NewKeyboardLayoutPickerContent fragment = new NewKeyboardLayoutPickerContent();
+        fragment.setControllerUpdateCallback(mControllerUpdateCallback);
         fragment.setArguments(getArguments());
         getActivity().getSupportFragmentManager()
                 .beginTransaction()
                 .replace(R.id.keyboard_layouts, fragment)
                 .commit();
-
         return fragmentView;
     }
 }