diff --git a/res/drawable/ic_qs_hbm.xml b/res/drawable/ic_qs_hbm.xml
new file mode 100644
index 0000000..57e43eb
--- /dev/null
+++ b/res/drawable/ic_qs_hbm.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/res/values/aospa_strings.xml b/res/values/aospa_strings.xml
index 6b66ea8..8129d43 100644
--- a/res/values/aospa_strings.xml
+++ b/res/values/aospa_strings.xml
@@ -54,4 +54,8 @@
Bluetooth is off
Tap a device to connect/disconnect
+
+ Force HBM
+ Auto brightness is off
+
diff --git a/res/values/config.xml b/res/values/config.xml
index dd59d62..e147ccd 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -8,7 +8,7 @@
- internet,wifi,cell,bt,flashlight,dnd,alarm,airplane,nfc,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,caffeine,dataswitch,heads_up,dc_dimming,aod,powershare
+ internet,wifi,cell,bt,flashlight,dnd,alarm,airplane,nfc,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,caffeine,dataswitch,heads_up,dc_dimming,aod,powershare,force_hbm
diff --git a/src/co/aospa/systemui/qs/tileimpl/ParanoidQSModule.kt b/src/co/aospa/systemui/qs/tileimpl/ParanoidQSModule.kt
index b808d6d..66d1839 100644
--- a/src/co/aospa/systemui/qs/tileimpl/ParanoidQSModule.kt
+++ b/src/co/aospa/systemui/qs/tileimpl/ParanoidQSModule.kt
@@ -24,6 +24,7 @@ import co.aospa.systemui.qs.tiles.CaffeineTile;
import co.aospa.systemui.qs.tiles.CellularTile
import co.aospa.systemui.qs.tiles.DataSwitchTile;
import co.aospa.systemui.qs.tiles.DcDimmingTile;
+import co.aospa.systemui.qs.tiles.ForceHbmTile;
import co.aospa.systemui.qs.tiles.HeadsUpTile;
import co.aospa.systemui.qs.tiles.PowerShareTile;
import co.aospa.systemui.qs.tiles.WifiTile
@@ -89,4 +90,10 @@ interface ParanoidQSModule {
@StringKey(WifiTile.TILE_SPEC)
fun bindWifiTile(wifiTile: WifiTile): QSTileImpl<*>
+ /** Inject ForceHbmTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ForceHbmTile.TILE_SPEC)
+ fun bindForceHbmTile(forceHbmTile: ForceHbmTile): QSTileImpl<*>
+
}
diff --git a/src/co/aospa/systemui/qs/tiles/ForceHbmTile.java b/src/co/aospa/systemui/qs/tiles/ForceHbmTile.java
new file mode 100644
index 0000000..ae05bb7
--- /dev/null
+++ b/src/co/aospa/systemui/qs/tiles/ForceHbmTile.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 The OmniROM Project
+ * 2020-2021 The LineageOS Project
+ * 2023 Paranoid Android
+ *
+ * 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 co.aospa.systemui.qs.tiles;
+
+import static com.android.internal.logging.MetricsLogger.VIEW_UNKNOWN;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.util.settings.SystemSettings;
+
+import javax.inject.Inject;
+
+public class ForceHbmTile extends QSTileImpl implements
+ BatteryController.BatteryStateChangeCallback {
+
+ public static final String TILE_SPEC = "force_hbm";
+
+ private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_hbm);
+ private final BatteryController mBatteryController;
+ private final SettingObserver mSetting, mBrightnessSetting;
+
+ @Inject
+ public ForceHbmTile(
+ QSHost host,
+ @Background Looper backgroundLooper,
+ @Main Handler mainHandler,
+ FalsingManager falsingManager,
+ MetricsLogger metricsLogger,
+ StatusBarStateController statusBarStateController,
+ ActivityStarter activityStarter,
+ QSLogger qsLogger,
+ SystemSettings systemSettings,
+ BatteryController batteryController,
+ UserTracker userTracker
+ ) {
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
+
+ mSetting = new SettingObserver(systemSettings, mHandler, Settings.System.FORCE_HBM,
+ userTracker.getUserId()) {
+ @Override
+ protected void handleValueChanged(int value, boolean observedChange) {
+ refreshState();
+ }
+ };
+
+ mBrightnessSetting = new SettingObserver(systemSettings, mHandler,
+ Settings.System.SCREEN_BRIGHTNESS_MODE, userTracker.getUserId()) {
+ @Override
+ protected void handleValueChanged(int value, boolean observedChange) {
+ refreshState();
+ }
+ };
+
+ mBatteryController = batteryController;
+ batteryController.observe(getLifecycle(), this);
+ }
+
+ @Override
+ public void onPowerSaveChanged(boolean isPowerSave) {
+ refreshState();
+ }
+
+ @Override
+ protected void handleDestroy() {
+ super.handleDestroy();
+ mSetting.setListening(false);
+ mBrightnessSetting.setListening(false);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true; // TODO: check if device supports hbm
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ BooleanState state = new BooleanState();
+ state.handlesLongClick = false;
+ return state;
+ }
+
+ @Override
+ public void handleSetListening(boolean listening) {
+ super.handleSetListening(listening);
+ mSetting.setListening(listening);
+ mBrightnessSetting.setListening(listening);
+ }
+
+ @Override
+ protected void handleUserSwitch(int newUserId) {
+ mSetting.setUserId(newUserId);
+ refreshState();
+ }
+
+ @Override
+ protected void handleClick(@Nullable View view) {
+ mSetting.setValue(mState.value ? 0 : 1);
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return null;
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.force_hbm);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final boolean enable = (mSetting.getValue() == 1);
+ if (state.slash == null) {
+ state.slash = new SlashState();
+ }
+ state.icon = mIcon;
+ state.value = enable;
+ state.slash.isSlashed = state.value;
+ state.label = mContext.getString(R.string.force_hbm);
+ if (mBatteryController.isPowerSave()) {
+ state.state = Tile.STATE_UNAVAILABLE;
+ state.secondaryLabel = mContext.getString(R.string.battery_detail_switch_title);
+ } else if (mBrightnessSetting.getValue() !=
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
+ state.state = Tile.STATE_UNAVAILABLE;
+ state.secondaryLabel = mContext.getString(R.string.auto_brightness_is_off);
+ } else {
+ state.state = enable ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.secondaryLabel = null;
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.QS_CUSTOM;
+ }
+}