Catalyst framework integration

Bug: 335132588
Flag: com.android.settingslib.flags.settings_catalyst
Test: Presubmit
Change-Id: Ic0f0193fd5cee144f2fab36ae5190156efb7bd10
diff --git a/Android.bp b/Android.bp
index 25fc8f56..8b903ba 100644
--- a/Android.bp
+++ b/Android.bp
@@ -111,7 +111,10 @@
         "keyboard_flags_lib",
     ],
 
-    plugins: ["androidx.room_room-compiler-plugin"],
+    plugins: [
+        "SettingsLibMetadata-processor",
+        "androidx.room_room-compiler-plugin",
+    ],
 
     errorprone: {
         extra_check_modules: ["//external/nullaway:nullaway_plugin"],
diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java
index d208fdf..7e008e4 100644
--- a/src/com/android/settings/SettingsApplication.java
+++ b/src/com/android/settings/SettingsApplication.java
@@ -16,6 +16,8 @@
 
 package com.android.settings;
 
+import static com.android.settingslib.flags.Flags.settingsCatalyst;
+
 import android.app.Application;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -42,13 +44,20 @@
 import com.android.settings.spa.SettingsSpaEnvironment;
 import com.android.settingslib.applications.AppIconCacheManager;
 import com.android.settingslib.datastore.BackupRestoreStorageManager;
+import com.android.settingslib.metadata.PreferenceScreenMetadata;
+import com.android.settingslib.metadata.PreferenceScreenRegistry;
+import com.android.settingslib.metadata.ProvidePreferenceScreenOptions;
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory;
 
 import com.google.android.setupcompat.util.WizardManagerHelper;
 
 import java.lang.ref.WeakReference;
+import java.util.List;
 
 /** Settings application which sets up activity embedding rules for the large screen device. */
+@ProvidePreferenceScreenOptions(
+        codegenCollector = "com.android.settings/PreferenceScreenCollector/get"
+)
 public class SettingsApplication extends Application {
 
     private WeakReference<SettingsHomepageActivity> mHomeActivity = new WeakReference<>(null);
@@ -64,6 +73,11 @@
     public void onCreate() {
         super.onCreate();
 
+        if (settingsCatalyst()) {
+            PreferenceScreenRegistry.INSTANCE.setPreferenceScreensSupplier(
+                    this::getPreferenceScreens);
+        }
+
         BackupRestoreStorageManager.getInstance(this)
                 .add(
                         new BatterySettingsStorage(this),
@@ -90,6 +104,13 @@
         registerActivityLifecycleCallbacks(new DeveloperOptionsActivityLifecycle());
     }
 
+    /** Returns the screens using metadata. */
+    protected List<PreferenceScreenMetadata> getPreferenceScreens() {
+        // PreferenceScreenCollector is generated by annotation processor from classes annotated
+        // with @ProvidePreferenceScreen
+        return PreferenceScreenCollector.get(this);
+    }
+
     @Override
     public void onTerminate() {
         BackupRestoreStorageManager.getInstance(this).removeAll();
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 0808da1..09dd1dd 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -15,6 +15,8 @@
  */
 package com.android.settings.dashboard;
 
+import static com.android.settingslib.flags.Flags.settingsCatalyst;
+
 import android.app.Activity;
 import android.app.settings.SettingsEnums;
 import android.content.ContentResolver;
@@ -53,6 +55,7 @@
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.metadata.PreferenceScreenRegistry;
 import com.android.settingslib.search.Indexable;
 
 import java.util.ArrayList;
@@ -97,30 +100,35 @@
                 R.array.config_suppress_injected_tile_keys));
         mDashboardFeatureProvider =
                 FeatureFactory.getFeatureFactory().getDashboardFeatureProvider();
-        // Load preference controllers from code
-        final List<AbstractPreferenceController> controllersFromCode =
-                createPreferenceControllers(context);
-        // Load preference controllers from xml definition
-        final List<BasePreferenceController> controllersFromXml = PreferenceControllerListHelper
-                .getPreferenceControllersFromXml(context, getPreferenceScreenResId());
-        // Filter xml-based controllers in case a similar controller is created from code already.
-        final List<BasePreferenceController> uniqueControllerFromXml =
-                PreferenceControllerListHelper.filterControllers(
-                        controllersFromXml, controllersFromCode);
 
-        // Add unique controllers to list.
-        if (controllersFromCode != null) {
-            mControllers.addAll(controllersFromCode);
-        }
-        mControllers.addAll(uniqueControllerFromXml);
+        if (!usePreferenceScreenMetadata() || PreferenceScreenRegistry.INSTANCE.get(
+                getPreferenceScreenBindingKey(context)) == null) {
+            // Load preference controllers from code
+            final List<AbstractPreferenceController> controllersFromCode =
+                    createPreferenceControllers(context);
+            // Load preference controllers from xml definition
+            final List<BasePreferenceController> controllersFromXml = PreferenceControllerListHelper
+                    .getPreferenceControllersFromXml(context, getPreferenceScreenResId());
+            // Filter xml-based controllers in case a similar controller is created from code
+            // already.
+            final List<BasePreferenceController> uniqueControllerFromXml =
+                    PreferenceControllerListHelper.filterControllers(
+                            controllersFromXml, controllersFromCode);
 
-        // And wire up with lifecycle.
-        final Lifecycle lifecycle = getSettingsLifecycle();
-        uniqueControllerFromXml.forEach(controller -> {
-            if (controller instanceof LifecycleObserver) {
-                lifecycle.addObserver((LifecycleObserver) controller);
+            // Add unique controllers to list.
+            if (controllersFromCode != null) {
+                mControllers.addAll(controllersFromCode);
             }
-        });
+            mControllers.addAll(uniqueControllerFromXml);
+
+            // And wire up with lifecycle.
+            final Lifecycle lifecycle = getSettingsLifecycle();
+            uniqueControllerFromXml.forEach(controller -> {
+                if (controller instanceof LifecycleObserver) {
+                    lifecycle.addObserver((LifecycleObserver) controller);
+                }
+            });
+        }
 
         // Set metrics category for BasePreferenceController.
         final int metricCategory = getMetricsCategory();
@@ -273,6 +281,11 @@
     }
 
     @Override
+    protected final int getPreferenceScreenResId(@NonNull Context context) {
+        return getPreferenceScreenResId();
+    }
+
+    @Override
     protected abstract int getPreferenceScreenResId();
 
     @Override
@@ -364,12 +377,32 @@
         if (resId <= 0) {
             return;
         }
-        addPreferencesFromResource(resId);
-        final PreferenceScreen screen = getPreferenceScreen();
+        PreferenceScreen screen;
+        if (usePreferenceScreenMetadata()) {
+            screen = createPreferenceScreen();
+            setPreferenceScreen(screen);
+            requireActivity().setTitle(screen.getTitle());
+        } else {
+            addPreferencesFromResource(resId);
+            screen = getPreferenceScreen();
+        }
         screen.setOnExpandButtonClickListener(this);
         displayResourceTilesToScreen(screen);
     }
 
+    @Override
+    protected final boolean usePreferenceScreenMetadata() {
+        return settingsCatalyst() && enableCatalyst();
+    }
+
+    /**
+     * Returns if settings catalyst should be enabled (e.g. check trunk stable flag) on current
+     * screen.
+     */
+    protected boolean enableCatalyst() {
+        return false;
+    }
+
     /**
      * Perform {@link AbstractPreferenceController#displayPreference(PreferenceScreen)}
      * on all {@link AbstractPreferenceController}s.