Separate "Keyboard" from "Language & input"

1. Separate "Keyboard" from "Language & input".
2. Use FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI to control the
   different UI until Settings launches the new UI design.

Bug: 242680328
Test: local test
Change-Id: Id1ea6d3e3c2e6b83bc4b4d835c6b27e31311c530
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index f1c1191..7ed95bc 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -111,6 +111,8 @@
     public static class SpellCheckersSettingsActivity extends SettingsActivity { /* empty */ }
     public static class LocalePickerActivity extends SettingsActivity { /* empty */ }
     public static class LanguageAndInputSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class LanguageSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class KeyboardSettingsActivity extends SettingsActivity { /* empty */ }
     public static class UserDictionarySettingsActivity extends SettingsActivity { /* empty */ }
     public static class DarkThemeSettingsActivity extends SettingsActivity { /* empty */ }
     public static class DisplaySettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 5e17e0b..c6f64d6 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -115,11 +115,13 @@
 import com.android.settings.gestures.SystemNavigationGestureSettings;
 import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment;
 import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
+import com.android.settings.inputmethod.KeyboardSettings;
 import com.android.settings.inputmethod.PhysicalKeyboardFragment;
 import com.android.settings.inputmethod.SpellCheckersSettings;
 import com.android.settings.inputmethod.UserDictionaryList;
 import com.android.settings.inputmethod.UserDictionarySettings;
 import com.android.settings.language.LanguageAndInputSettings;
+import com.android.settings.language.LanguageSettings;
 import com.android.settings.localepicker.LocaleListEditor;
 import com.android.settings.location.LocationServices;
 import com.android.settings.location.LocationSettings;
@@ -205,6 +207,8 @@
             LocaleListEditor.class.getName(),
             AvailableVirtualKeyboardFragment.class.getName(),
             LanguageAndInputSettings.class.getName(),
+            LanguageSettings.class.getName(),
+            KeyboardSettings.class.getName(),
             SpellCheckersSettings.class.getName(),
             UserDictionaryList.class.getName(),
             UserDictionarySettings.class.getName(),
@@ -383,6 +387,8 @@
             Settings.LocationSettingsActivity.class.getName(),
             // Home page > System
             Settings.LanguageAndInputSettingsActivity.class.getName(),
+            Settings.LanguageSettingsActivity.class.getName(),
+            Settings.KeyboardSettingsActivity.class.getName(),
             Settings.DateTimeSettingsActivity.class.getName(),
             Settings.EnterprisePrivacySettingsActivity.class.getName(),
             Settings.MyDeviceInfoActivity.class.getName(),
diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
index c2b5198..a2b1454 100644
--- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
+++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
@@ -101,6 +101,7 @@
                 SystemDashboardFragment.class.getName(), CategoryKey.CATEGORY_SYSTEM);
         PARENT_TO_CATEGORY_KEY_MAP.put(LanguageAndInputSettings.class.getName(),
                 CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
+        // TODO(b/242680328) Tie new category key to LanguageSettings and KeyboardSettings page
         PARENT_TO_CATEGORY_KEY_MAP.put(DevelopmentSettingsDashboardFragment.class.getName(),
                 CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
         PARENT_TO_CATEGORY_KEY_MAP.put(ConfigureNotificationSettings.class.getName(),
diff --git a/src/com/android/settings/inputmethod/KeyboardPreferenceController.java b/src/com/android/settings/inputmethod/KeyboardPreferenceController.java
new file mode 100644
index 0000000..75351b1
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardPreferenceController.java
@@ -0,0 +1,95 @@
+/*
+ * 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.settings.inputmethod;
+
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.util.FeatureFlagUtils;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+
+import java.util.List;
+
+public class KeyboardPreferenceController extends BasePreferenceController
+        implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause,
+        InputManager.InputDeviceListener {
+
+    private final InputManager mIm;
+
+    private Preference mPreference;
+
+    public KeyboardPreferenceController(Context context, String key) {
+        super(context, key);
+        mIm = context.getSystemService(InputManager.class);
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        updateSummary();
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        updateSummary();
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        updateSummary();
+    }
+
+    @Override
+    public void onPause() {
+        mIm.unregisterInputDeviceListener(this);
+    }
+
+    @Override
+    public void onResume() {
+        mIm.registerInputDeviceListener(this, null);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        mPreference = preference;
+        updateSummary();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        boolean isFeatureOn = FeatureFlagUtils
+                .isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
+        return isFeatureOn ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+
+    private void updateSummary() {
+        final List<HardKeyboardDeviceInfo> keyboards =
+                PhysicalKeyboardFragment.getHardKeyboards(mContext);
+        if (keyboards.isEmpty()) {
+            mPreference.setSummary(R.string.keyboard_settings_summary);
+        } else {
+            mPreference.setSummary(R.string.keyboard_settings_with_physical_keyboard_summary);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/inputmethod/KeyboardSettings.java b/src/com/android/settings/inputmethod/KeyboardSettings.java
new file mode 100644
index 0000000..2d6ac88
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardSettings.java
@@ -0,0 +1,136 @@
+/*
+ * 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.settings.inputmethod;
+
+import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_DICTIONARY_FOR_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.SPELL_CHECKER_FOR_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_KEYBOARDS_AND_TOOLS;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.FeatureFlagUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.language.DefaultVoiceInputPreferenceController;
+import com.android.settings.language.PointerSpeedController;
+import com.android.settings.language.TtsPreferenceController;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@SearchIndexable
+public class KeyboardSettings extends DashboardFragment {
+
+    private static final String TAG = "KeyboardSettings";
+
+    private static final String KEY_KEYBOARDS_CATEGORY = "keyboards_category";
+    private static final String KEY_SPEECH_CATEGORY = "speech_category";
+    private static final String KEY_TEXT_TO_SPEECH = "tts_settings_summary";
+    private static final String KEY_POINTER_CATEGORY = "pointer_category";
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_KEYBOARDS_CATEGORY;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        replaceEnterpriseStringTitle("language_and_input_for_work_category",
+                WORK_PROFILE_KEYBOARDS_AND_TOOLS,
+                R.string.language_and_input_for_work_category_title);
+        replaceEnterpriseStringTitle("spellcheckers_settings_for_work_pref",
+                SPELL_CHECKER_FOR_WORK,
+                R.string.spellcheckers_settings_for_work_title);
+        replaceEnterpriseStringTitle("user_dictionary_settings_for_work_pref",
+                PERSONAL_DICTIONARY_FOR_WORK,
+                R.string.user_dict_settings_for_work_title);
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.keyboard_settings;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        return buildPreferenceControllers(context, getSettingsLifecycle());
+    }
+
+    private static List<AbstractPreferenceController> buildPreferenceControllers(
+            @NonNull Context context, @Nullable Lifecycle lifecycle) {
+        final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        // Input
+        final VirtualKeyboardPreferenceController virtualKeyboardPreferenceController =
+                new VirtualKeyboardPreferenceController(context);
+        final PhysicalKeyboardPreferenceController physicalKeyboardPreferenceController =
+                new PhysicalKeyboardPreferenceController(context, lifecycle);
+        controllers.add(virtualKeyboardPreferenceController);
+        controllers.add(physicalKeyboardPreferenceController);
+        controllers.add(new PreferenceCategoryController(context,
+                KEY_KEYBOARDS_CATEGORY).setChildren(
+                Arrays.asList(virtualKeyboardPreferenceController,
+                        physicalKeyboardPreferenceController)));
+
+        // Speech
+        final DefaultVoiceInputPreferenceController defaultVoiceInputPreferenceController =
+                new DefaultVoiceInputPreferenceController(context, lifecycle);
+        final TtsPreferenceController ttsPreferenceController =
+                new TtsPreferenceController(context, KEY_TEXT_TO_SPEECH);
+        controllers.add(defaultVoiceInputPreferenceController);
+        controllers.add(ttsPreferenceController);
+        controllers.add(new PreferenceCategoryController(context,
+                KEY_SPEECH_CATEGORY).setChildren(
+                Arrays.asList(defaultVoiceInputPreferenceController, ttsPreferenceController)));
+
+        // Pointer
+        final PointerSpeedController pointerController = new PointerSpeedController(context);
+        controllers.add(pointerController);
+        controllers.add(new PreferenceCategoryController(context,
+                KEY_POINTER_CATEGORY).setChildren(Arrays.asList(pointerController)));
+
+        // Input Assistance
+        controllers.add(new SpellCheckerPreferenceController(context));
+
+        return controllers;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.keyboard_settings) {
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return FeatureFlagUtils
+                            .isEnabled(context, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
+                }
+            };
+}
\ No newline at end of file
diff --git a/src/com/android/settings/language/LanguageAndInputPreferenceController.java b/src/com/android/settings/language/LanguageAndInputPreferenceController.java
index 04bf622..691d907 100644
--- a/src/com/android/settings/language/LanguageAndInputPreferenceController.java
+++ b/src/com/android/settings/language/LanguageAndInputPreferenceController.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageManager;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 
@@ -41,7 +42,9 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE;
+        boolean isFeatureOn = FeatureFlagUtils
+                .isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
+        return isFeatureOn ? CONDITIONALLY_UNAVAILABLE : AVAILABLE;
     }
 
     @Override
diff --git a/src/com/android/settings/language/LanguageAndInputSettings.java b/src/com/android/settings/language/LanguageAndInputSettings.java
index 2d80da5..f40473c 100644
--- a/src/com/android/settings/language/LanguageAndInputSettings.java
+++ b/src/com/android/settings/language/LanguageAndInputSettings.java
@@ -24,6 +24,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.Bundle;
+import android.util.FeatureFlagUtils;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -104,8 +105,6 @@
     private static List<AbstractPreferenceController> buildPreferenceControllers(
             @NonNull Context context, @Nullable Lifecycle lifecycle) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
-        // Language
-        controllers.add(new PhoneLanguagePreferenceController(context));
 
         // Input
         final VirtualKeyboardPreferenceController virtualKeyboardPreferenceController =
@@ -154,11 +153,16 @@
 
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider(R.xml.language_and_input) {
-
                 @Override
                 public List<AbstractPreferenceController> createPreferenceControllers(
                         Context context) {
                     return buildPreferenceControllers(context, null);
                 }
+
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return !FeatureFlagUtils
+                            .isEnabled(context, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
+                }
             };
 }
diff --git a/src/com/android/settings/language/LanguagePreferenceController.java b/src/com/android/settings/language/LanguagePreferenceController.java
new file mode 100644
index 0000000..08033cd
--- /dev/null
+++ b/src/com/android/settings/language/LanguagePreferenceController.java
@@ -0,0 +1,36 @@
+/*
+ * 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.settings.language;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class LanguagePreferenceController extends BasePreferenceController {
+
+    public LanguagePreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        boolean isFeatureOn = FeatureFlagUtils
+                .isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
+        return isFeatureOn ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/language/LanguageSettings.java b/src/com/android/settings/language/LanguageSettings.java
new file mode 100644
index 0000000..f814e36
--- /dev/null
+++ b/src/com/android/settings/language/LanguageSettings.java
@@ -0,0 +1,70 @@
+/*
+ * 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.settings.language;
+
+import android.app.Activity;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+@SearchIndexable
+public class LanguageSettings extends DashboardFragment {
+
+    private static final String TAG = "LanguageSettings";
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_LANGUAGES_CATEGORY;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        // Hack to update action bar title. It's necessary to refresh title because this page user
+        // can change locale from here and fragment won't relaunch. Once language changes, title
+        // must display in the new language.
+        final Activity activity = getActivity();
+        if (activity == null) {
+            return;
+        }
+        activity.setTitle(R.string.languages_settings);
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.language_settings;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.language_settings) {
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return FeatureFlagUtils
+                            .isEnabled(context, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
+                }
+            };
+}
\ No newline at end of file
diff --git a/src/com/android/settings/language/PhoneLanguagePreferenceController.java b/src/com/android/settings/language/PhoneLanguagePreferenceController.java
index 4f67a8f..0d5aa37 100644
--- a/src/com/android/settings/language/PhoneLanguagePreferenceController.java
+++ b/src/com/android/settings/language/PhoneLanguagePreferenceController.java
@@ -16,33 +16,32 @@
 
 package com.android.settings.language;
 
-import android.app.settings.SettingsEnums;
 import android.content.Context;
 
 import androidx.preference.Preference;
 
 import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.localepicker.LocaleListEditor;
 import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.AbstractPreferenceController;
 
 import java.util.List;
 
-public class PhoneLanguagePreferenceController extends AbstractPreferenceController
+public class PhoneLanguagePreferenceController extends BasePreferenceController
         implements PreferenceControllerMixin {
 
-    private static final String KEY_PHONE_LANGUAGE = "phone_language";
-
-    public PhoneLanguagePreferenceController(Context context) {
-        super(context);
+    public PhoneLanguagePreferenceController(Context context, String key) {
+        super(context, key);
     }
 
     @Override
-    public boolean isAvailable() {
-        return mContext.getResources().getBoolean(R.bool.config_show_phone_language)
-                && mContext.getAssets().getLocales().length > 1;
+    public int getAvailabilityStatus() {
+        if (mContext.getResources().getBoolean(R.bool.config_show_phone_language)
+                && mContext.getAssets().getLocales().length > 1) {
+            return AVAILABLE;
+        } else {
+            return CONDITIONALLY_UNAVAILABLE;
+        }
     }
 
     @Override
@@ -61,23 +60,4 @@
         // make search page look like there are duplicate result, creating confusion.
         keys.add(getPreferenceKey());
     }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY_PHONE_LANGUAGE;
-    }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (!KEY_PHONE_LANGUAGE.equals(preference.getKey())) {
-            return false;
-        }
-        new SubSettingLauncher(mContext)
-                .setDestination(LocaleListEditor.class.getName())
-                .setSourceMetricsCategory(SettingsEnums.SETTINGS_LANGUAGE_CATEGORY)
-                .setTitleRes(R.string.language_picker_title)
-                .launch();
-        return true;
-    }
-
 }