OmniLib: Add omnirom health IFastCharge interface support

Change-Id: I89eb3efbc79146b08684fa41f3c8d62ef2fb60c4
Signed-off-by: micky387 <mickaelsaibi@free.fr>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index a67890b..7dfb977 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -26,4 +26,17 @@
         <item>reboot_bootloader</item>
     </string-array>
 
+    <!-- Fast charge -->
+    <string-array name="charging_speed_entries" translatable="false">
+        <item>@string/charging_speed_slow</item>
+        <item>@string/charging_speed_fast</item>
+        <item>@string/charging_speed_super_fast</item>
+    </string-array>
+
+    <string-array name="charging_speed_values" translatable="false">
+        <item>1</item> <!-- FastChargeMode.NONE -->
+        <item>2</item> <!-- FastChargeMode.FAST_CHARGE -->
+        <item>4</item> <!-- FastChargeMode.SUPER_FAST_CHARGE -->
+    </string-array>
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b0c80c7..f0d46be 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -45,4 +45,10 @@
     <string name="charging_control_notification_content_limit_reached">Battery is charged to %1$d%%</string>
     <string name="charging_control_notification_content_target">Battery will be fully charged at %1$s</string>
     <string name="charging_control_notification_content_target_reached">Battery is charged</string>
+
+    <!-- Charging speed strings -->
+    <string name="charging_speed">Charging speed</string>
+    <string name="charging_speed_slow">Slow</string>
+    <string name="charging_speed_fast">Fast</string>
+    <string name="charging_speed_super_fast">Super fast</string>
 </resources>
diff --git a/res/values/symbols.xml b/res/values/symbols.xml
index dc60521..cdc8cec 100644
--- a/res/values/symbols.xml
+++ b/res/values/symbols.xml
@@ -71,4 +71,9 @@
     <java-symbol type="string" name="charging_control_notification_content_target" />
     <java-symbol type="string" name="charging_control_notification_content_target_reached" />
 
+     <!-- Charging speed -->
+    <java-symbol type="string" name="charging_speed" />
+    <java-symbol type="array" name="charging_speed_entries" />
+    <java-symbol type="array" name="charging_speed_values" />
+
 </resources>
diff --git a/sdk/src/omnirom/health/HealthInterface.java b/sdk/src/omnirom/health/HealthInterface.java
index 4589285..0f1b3b3 100644
--- a/sdk/src/omnirom/health/HealthInterface.java
+++ b/sdk/src/omnirom/health/HealthInterface.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The LineageOS Project
+ * Copyright (C) 2023-2025 The LineageOS Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -294,4 +294,65 @@
             return false;
         }
     }
+
+    /**
+     * Returns whether fast charge is supported
+     *
+     * @return true if fast charge is supported
+     */
+    public boolean isFastChargeSupported() {
+        try {
+            return checkService() && sService.isFastChargeSupported();
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getLocalizedMessage(), e);
+        }
+
+        return false;
+    }
+
+    /**
+     * Gets supported fast charge mode
+     *
+     * @return true supported fast charge modes
+     */
+    public int[] getSupportedFastChargeModes() {
+        try {
+            return checkService() ? sService.getSupportedFastChargeModes() : new int[0];
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getLocalizedMessage(), e);
+        }
+
+        return new int[0];
+    }
+
+    /**
+     * Gets current fast charge mode
+     *
+     * @return true current fast charge mode
+     */
+    public int getFastChargeMode() {
+        try {
+            return checkService() ? sService.getFastChargeMode() : 0;
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getLocalizedMessage(), e);
+        }
+
+        return 0;
+    }
+
+    /**
+     * Sets selected fast charge mode
+     *
+     * @param mode the fast charge mode
+     * @return true if fast charge was set
+     */
+    public boolean setFastChargeMode(int mode) {
+        try {
+            return checkService() && sService.setFastChargeMode(mode);
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getLocalizedMessage(), e);
+        }
+
+        return false;
+    }
 }
diff --git a/sdk/src/omnirom/health/IHealthInterface.aidl b/sdk/src/omnirom/health/IHealthInterface.aidl
index 30928c5..2736673 100644
--- a/sdk/src/omnirom/health/IHealthInterface.aidl
+++ b/sdk/src/omnirom/health/IHealthInterface.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2023 The LineageOS Project
+ * Copyright (c) 2023-2025 The LineageOS Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -37,4 +37,9 @@
 
     boolean resetChargingControl();
     boolean allowFineGrainedSettings();
+
+    boolean isFastChargeSupported();
+    int[] getSupportedFastChargeModes();
+    int getFastChargeMode();
+    boolean setFastChargeMode(int mode);
 }
diff --git a/src/org/omnirom/omnilib/internal/health/FastChargeController.java b/src/org/omnirom/omnilib/internal/health/FastChargeController.java
new file mode 100644
index 0000000..2ff610f
--- /dev/null
+++ b/src/org/omnirom/omnilib/internal/health/FastChargeController.java
@@ -0,0 +1,131 @@
+/*
+ * SPDX-FileCopyrightText: 2025 The LineageOS Project
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.omnirom.omnilib.internal.health;
+
+import android.content.res.Resources;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.util.ArrayUtils;
+
+import org.omnirom.omnilib.R;
+import org.omnirom.omnilib.utils.OmniSettings;
+
+import vendor.lineage.health.FastChargeMode;
+import vendor.lineage.health.IFastCharge;
+
+import java.io.PrintWriter;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FastChargeController extends OmniRomHealthFeature {
+    private final int[] mChargingSpeedValues;
+    private final ContentResolver mContentResolver;
+    private final IFastCharge mFastCharge;
+
+    // Settings uris
+    private final Uri MODE_URI = Settings.System.getUriFor(
+            OmniSettings.OMNI_FAST_CHARGE_MODE);
+
+    public FastChargeController(Context context, Handler handler) {
+        super(context, handler);
+
+        mContentResolver = mContext.getContentResolver();
+        mFastCharge = IFastCharge.Stub.asInterface(
+                ServiceManager.waitForDeclaredService(
+                        IFastCharge.DESCRIPTOR + "/default"));
+
+        Resources res = mContext.getResources();
+        mChargingSpeedValues = Stream.of(res.getStringArray(R.array.charging_speed_values))
+                .mapToInt(Integer::parseInt)
+                .toArray();
+
+        if (mFastCharge == null) {
+            Log.i(TAG, "Lineage Health HAL not found");
+            return;
+        }
+    }
+
+    @Override
+    public boolean isSupported() {
+        try {
+            return mFastCharge != null && mFastCharge.getSupportedFastChargeModes() > 0;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public int[] getSupportedFastChargeModes() {
+        try {
+            long supportedFastChargeModes = mFastCharge.getSupportedFastChargeModes();
+
+            return IntStream.of(mChargingSpeedValues)
+                    .filter(mode -> (supportedFastChargeModes & mode) != 0)
+                    .toArray();
+        } catch (RemoteException e) {
+            return new int[0];
+        }
+    }
+
+    public int getFastChargeMode() {
+        int[] supportedFastChargeModes = getSupportedFastChargeModes();
+        int defaultMode = supportedFastChargeModes[supportedFastChargeModes.length - 1];
+
+        int mode = Settings.System.getInt(mContentResolver,
+                OmniSettings.OMNI_FAST_CHARGE_MODE,
+                defaultMode);
+        if (mode != defaultMode && !ArrayUtils.contains(supportedFastChargeModes, mode)) {
+            return defaultMode;
+        }
+
+        return mode;
+    }
+
+    public boolean setFastChargeMode(int mode) {
+        putInt(OmniSettings.OMNI_FAST_CHARGE_MODE, mode);
+        return true;
+    }
+
+    @Override
+    public void onStart() {
+        if (mFastCharge == null) {
+            return;
+        }
+
+        // Register setting observer
+        registerSettings(MODE_URI);
+
+        handleSettingChange();
+    }
+
+    private void handleSettingChange() {
+        try {
+            mFastCharge.setFastChargeMode(getFastChargeMode());
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
+    protected void onSettingsChanged(Uri uri) {
+        handleSettingChange();
+    }
+
+    @Override
+    public void dump(PrintWriter pw) {
+        pw.println();
+        pw.println("FastChargeController Configuration:");
+        pw.println("  Mode: " + getFastChargeMode());
+        pw.println();
+    }
+}
diff --git a/src/org/omnirom/omnilib/internal/health/HealthInterfaceService.java b/src/org/omnirom/omnilib/internal/health/HealthInterfaceService.java
index 373f132..09148a1 100644
--- a/src/org/omnirom/omnilib/internal/health/HealthInterfaceService.java
+++ b/src/org/omnirom/omnilib/internal/health/HealthInterfaceService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The LineageOS Project
+ * Copyright (C) 2023-2025 The LineageOS Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -47,6 +47,7 @@
 
     // Health features
     private ChargingControlController mCCC;
+    private FastChargeController mFCC;
 
     public HealthInterfaceService(Context context) {
         super(context);
@@ -79,6 +80,10 @@
         if (mCCC.isSupported()) {
             mFeatures.add(mCCC);
         }
+        mFCC = new FastChargeController(mContext, mHandler);
+        if (mFCC.isSupported()) {
+            mFeatures.add(mFCC);
+        }
 
         if (!mFeatures.isEmpty()) {
             publishBinderService(OmniRomContextConstants.LINEAGE_HEALTH_INTERFACE, mService);
@@ -168,6 +173,26 @@
         }
 
         @Override
+        public boolean isFastChargeSupported() {
+            return mFCC.isSupported();
+        }
+
+        @Override
+        public int[] getSupportedFastChargeModes() {
+            return mFCC.getSupportedFastChargeModes();
+        }
+
+        @Override
+        public int getFastChargeMode() {
+            return mFCC.getFastChargeMode();
+        }
+
+        @Override
+        public boolean setFastChargeMode(int mode) {
+            return mFCC.setFastChargeMode(mode);
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP, TAG);
 
diff --git a/src/org/omnirom/omnilib/utils/OmniSettings.java b/src/org/omnirom/omnilib/utils/OmniSettings.java
index 7b6c567..6cd3d79 100644
--- a/src/org/omnirom/omnilib/utils/OmniSettings.java
+++ b/src/org/omnirom/omnilib/utils/OmniSettings.java
@@ -233,7 +233,6 @@
     public static final String OMNI_LOCKSCREEN_DND_ENABLED = "lockscreen_dnd_enabled";
 
     /**
-     * @hide
      * Whether the phone vibrates on call connect
      * @hide
      */
@@ -254,32 +253,43 @@
     /**
      * Whether charging control should be enabled.
      * The value is boolean (1 or 0).
+     * @hide
      */
     public static final String OMNI_CHARGING_CONTROL_ENABLED = "charging_control_enabled";
 
     /**
      * Charging control mode, one of AUTO (1; default), CUSTOM (2), or LIMIT (3).
+     * @hide
      */
     public static final String OMNI_CHARGING_CONTROL_MODE = "charging_control_mode";
 
     /**
      * Time when charging control is automatically activated in CUSTOM mode.
      * The value is represented as seconds from midnight.
+     * @hide
      */
     public static final String OMNI_CHARGING_CONTROL_START_TIME = "charging_control_start_time";
 
     /**
      * Target time when battery is fully charged in CUSTOM mode.
      * The value is represented as seconds from midnight.
+     * @hide
      */
     public static final String OMNI_CHARGING_CONTROL_TARGET_TIME = "charging_control_target_time";
 
     /**
      * Limit to stop charging.
+     * @hide
      */
     public static final String OMNI_CHARGING_CONTROL_LIMIT = "charging_control_charging_limit";
 
     /**
+     * Fast charging mode
+     * @hide
+     */
+    public static final String OMNI_FAST_CHARGE_MODE = "fast_charge_mode";
+
+    /**
      * SettingsBackupAgent will combine its list with this so we dont need
      * to add new things into SettingsProvider SystemSettings
      * @hide
@@ -326,6 +336,7 @@
         OMNI_CHARGING_CONTROL_START_TIME,
         OMNI_CHARGING_CONTROL_TARGET_TIME,
         OMNI_CHARGING_CONTROL_LIMIT,
+        OMNI_FAST_CHARGE_MODE,
     };
 
     /**
@@ -338,6 +349,7 @@
      * OMNI_CHARGING_CONTROL_LIMIT_VALIDATOR == 3
      * OMNI_CHARGING_CONTROL_MODE_VALIDATOR == 4
      * OMNI_CHARGING_CONTROL_TIME_VALIDATOR == 5
+     * OMNI_FAST_CHARGE_MODE == 6 {FastChargeMode (NONE|FAST_CHARGE|SUPER_FAST_CHARGE)}
      * @hide
      */
     public static final Map<String, Integer> OMNI_SETTINGS_VALIDATORS = new ArrayMap<>();
@@ -385,5 +397,6 @@
         OMNI_SETTINGS_VALIDATORS.put(OMNI_CHARGING_CONTROL_MODE, 4);
         OMNI_SETTINGS_VALIDATORS.put(OMNI_CHARGING_CONTROL_START_TIME, 5);
         OMNI_SETTINGS_VALIDATORS.put(OMNI_CHARGING_CONTROL_TARGET_TIME, 5);
+        OMNI_SETTINGS_VALIDATORS.put(OMNI_FAST_CHARGE_MODE, 6);
     }
 }