diff --git a/parts/res/drawable/ic_doze_brightness_auto.xml b/parts/res/drawable/ic_doze_brightness_auto.xml new file mode 100644 index 0000000..81d74f5 --- /dev/null +++ b/parts/res/drawable/ic_doze_brightness_auto.xml @@ -0,0 +1,9 @@ + + + + diff --git a/parts/res/drawable/ic_doze_brightness_high.xml b/parts/res/drawable/ic_doze_brightness_high.xml new file mode 100644 index 0000000..43dc498 --- /dev/null +++ b/parts/res/drawable/ic_doze_brightness_high.xml @@ -0,0 +1,9 @@ + + + + diff --git a/parts/res/drawable/ic_doze_brightness_low.xml b/parts/res/drawable/ic_doze_brightness_low.xml new file mode 100644 index 0000000..ec13c12 --- /dev/null +++ b/parts/res/drawable/ic_doze_brightness_low.xml @@ -0,0 +1,9 @@ + + + + diff --git a/parts/res/values/arrays.xml b/parts/res/values/arrays.xml new file mode 100644 index 0000000..46137ab --- /dev/null +++ b/parts/res/values/arrays.xml @@ -0,0 +1,28 @@ + + + + + Low brightness + High brightness + Adaptive brightness + + + 0 + 1 + 2 + + diff --git a/parts/res/values/strings.xml b/parts/res/values/strings.xml new file mode 100644 index 0000000..d9249a3 --- /dev/null +++ b/parts/res/values/strings.xml @@ -0,0 +1,20 @@ + + + + Doze brightness + %s mode is enabled + diff --git a/parts/res/xml/doze_settings.xml b/parts/res/xml/doze_settings.xml index 3a068c0..01ef6c0 100644 --- a/parts/res/xml/doze_settings.xml +++ b/parts/res/xml/doze_settings.xml @@ -25,6 +25,14 @@ android:summary="@string/ambient_display_always_on_summary" android:persistent="false" /> + + diff --git a/parts/src/org/lineageos/settings/BootCompletedReceiver.java b/parts/src/org/lineageos/settings/BootCompletedReceiver.java index 672621e..08b9f1d 100644 --- a/parts/src/org/lineageos/settings/BootCompletedReceiver.java +++ b/parts/src/org/lineageos/settings/BootCompletedReceiver.java @@ -32,6 +32,6 @@ public class BootCompletedReceiver extends BroadcastReceiver { public void onReceive(final Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Received boot completed intent"); - DozeUtils.checkDozeService(context); + DozeUtils.onBootCompleted(context); } } diff --git a/parts/src/org/lineageos/settings/doze/AodSensor.java b/parts/src/org/lineageos/settings/doze/AodSensor.java new file mode 100644 index 0000000..0cb6a16 --- /dev/null +++ b/parts/src/org/lineageos/settings/doze/AodSensor.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 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. + * 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 org.lineageos.settings.doze; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.SystemClock; +import android.util.Log; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class AodSensor implements SensorEventListener { + private static final boolean DEBUG = false; + private static final String TAG = "AodSensor"; + + private SensorManager mSensorManager; + private Sensor mSensor; + private Context mContext; + private ExecutorService mExecutorService; + + public AodSensor(Context context) { + mContext = context; + mSensorManager = mContext.getSystemService(SensorManager.class); + mSensor = DozeUtils.getSensor(mSensorManager, "xiaomi.sensor.aod"); + mExecutorService = Executors.newSingleThreadExecutor(); + } + + private Future submit(Runnable runnable) { return mExecutorService.submit(runnable); } + + @Override + public void onSensorChanged(SensorEvent event) { + if (DEBUG) { + Log.d(TAG, "Got sensor event: " + event.values[0]); + } + + if (event.values[0] == 3 || event.values[0] == 5) { + DozeUtils.setDozeMode(DozeUtils.DOZE_MODE_LBM); + } else if (event.values[0] == 4) { + DozeUtils.setDozeMode(DozeUtils.DOZE_MODE_HBM); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + /* Empty */ + } + + protected void enable() { + if (DEBUG) { + Log.d(TAG, "Enabling"); + } + submit(() -> { + mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL); + }); + } + + protected void disable() { + if (DEBUG) { + Log.d(TAG, "Disabling"); + } + submit(() -> { mSensorManager.unregisterListener(this, mSensor); }); + } +} diff --git a/parts/src/org/lineageos/settings/doze/DozeService.java b/parts/src/org/lineageos/settings/doze/DozeService.java index 0c9c61a..84641e1 100644 --- a/parts/src/org/lineageos/settings/doze/DozeService.java +++ b/parts/src/org/lineageos/settings/doze/DozeService.java @@ -29,6 +29,7 @@ public class DozeService extends Service { private static final String TAG = "DozeService"; private static final boolean DEBUG = false; + private AodSensor mAodSensor; private ProximitySensor mProximitySensor; private PickupSensor mPickupSensor; @@ -36,6 +37,7 @@ public class DozeService extends Service { public void onCreate() { if (DEBUG) Log.d(TAG, "Creating service"); + mAodSensor = new AodSensor(this); mProximitySensor = new ProximitySensor(this); mPickupSensor = new PickupSensor(this); @@ -76,6 +78,9 @@ public class DozeService extends Service { if (DozeUtils.isHandwaveGestureEnabled(this) || DozeUtils.isPocketGestureEnabled(this)) { mProximitySensor.disable(); } + if (DozeUtils.isDozeAutoBrightnessEnabled(this)) { + mAodSensor.disable(); + } } private void onDisplayOff() { @@ -87,6 +92,9 @@ public class DozeService extends Service { if (DozeUtils.isHandwaveGestureEnabled(this) || DozeUtils.isPocketGestureEnabled(this)) { mProximitySensor.enable(); } + if (DozeUtils.isDozeAutoBrightnessEnabled(this)) { + mAodSensor.enable(); + } } private BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() { diff --git a/parts/src/org/lineageos/settings/doze/DozeSettingsFragment.java b/parts/src/org/lineageos/settings/doze/DozeSettingsFragment.java index ea229a5..69dbd4f 100644 --- a/parts/src/org/lineageos/settings/doze/DozeSettingsFragment.java +++ b/parts/src/org/lineageos/settings/doze/DozeSettingsFragment.java @@ -34,6 +34,7 @@ import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.Switch; import android.widget.TextView; +import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.Preference.OnPreferenceChangeListener; import androidx.preference.PreferenceCategory; @@ -48,6 +49,7 @@ public class DozeSettingsFragment extends PreferenceFragment private View mSwitchBar; private SwitchPreference mAlwaysOnDisplayPreference; + private ListPreference mDozeBrightnessPreference; private SwitchPreference mWakeOnGesturePreference; private SwitchPreference mPickUpPreference; private SwitchPreference mHandwavePreference; @@ -74,6 +76,11 @@ public class DozeSettingsFragment extends PreferenceFragment mAlwaysOnDisplayPreference.setChecked(DozeUtils.isAlwaysOnEnabled(getActivity())); mAlwaysOnDisplayPreference.setOnPreferenceChangeListener(this); + mDozeBrightnessPreference = (ListPreference) findPreference(DozeUtils.DOZE_BRIGHTNESS_KEY); + mDozeBrightnessPreference.setEnabled( + dozeEnabled && DozeUtils.isAlwaysOnEnabled(getActivity())); + mDozeBrightnessPreference.setOnPreferenceChangeListener(this); + mWakeOnGesturePreference = (SwitchPreference) findPreference(DozeUtils.WAKE_ON_GESTURE_KEY); mWakeOnGesturePreference.setEnabled(dozeEnabled); mWakeOnGesturePreference.setOnPreferenceChangeListener(this); @@ -105,6 +112,7 @@ public class DozeSettingsFragment extends PreferenceFragment // Hide AOD if not supported and set all its dependents otherwise if (!DozeUtils.alwaysOnDisplayAvailable(getActivity())) { getPreferenceScreen().removePreference(mAlwaysOnDisplayPreference); + getPreferenceScreen().removePreference(mDozeBrightnessPreference); } else { mWakeOnGesturePreference.setDependency(DozeUtils.ALWAYS_ON_DISPLAY); pickupSensorCategory.setDependency(DozeUtils.ALWAYS_ON_DISPLAY); @@ -146,6 +154,29 @@ public class DozeSettingsFragment extends PreferenceFragment public boolean onPreferenceChange(Preference preference, Object newValue) { if (DozeUtils.ALWAYS_ON_DISPLAY.equals(preference.getKey())) { DozeUtils.enableAlwaysOn(getActivity(), (Boolean) newValue); + if (!(Boolean) newValue) { + mDozeBrightnessPreference.setValue(DozeUtils.DOZE_BRIGHTNESS_LBM); + } else { + mPickUpPreference.setChecked(false); + mHandwavePreference.setChecked(false); + mPocketPreference.setChecked(false); + } + mDozeBrightnessPreference.setEnabled((Boolean) newValue); + } else if (DozeUtils.DOZE_BRIGHTNESS_KEY.equals(preference.getKey())) { + if (!DozeUtils.DOZE_BRIGHTNESS_AUTO.equals((String) newValue)) { + DozeUtils.setDozeMode((String) newValue); + } + switch ((String) newValue) { + case DozeUtils.DOZE_BRIGHTNESS_LBM: + mDozeBrightnessPreference.setIcon(R.drawable.ic_doze_brightness_low); + break; + case DozeUtils.DOZE_BRIGHTNESS_HBM: + mDozeBrightnessPreference.setIcon(R.drawable.ic_doze_brightness_high); + break; + case DozeUtils.DOZE_BRIGHTNESS_AUTO: + mDozeBrightnessPreference.setIcon(R.drawable.ic_doze_brightness_auto); + break; + } } mHandler.post(() -> DozeUtils.checkDozeService(getActivity())); @@ -164,8 +195,14 @@ public class DozeSettingsFragment extends PreferenceFragment if (!isChecked) { DozeUtils.enableAlwaysOn(getActivity(), false); mAlwaysOnDisplayPreference.setChecked(false); + mDozeBrightnessPreference.setValue(DozeUtils.DOZE_BRIGHTNESS_LBM); + mPickUpPreference.setChecked(false); + mHandwavePreference.setChecked(false); + mPocketPreference.setChecked(false); } mAlwaysOnDisplayPreference.setEnabled(isChecked); + mDozeBrightnessPreference.setEnabled( + isChecked && DozeUtils.isAlwaysOnEnabled(getActivity())); mWakeOnGesturePreference.setEnabled(isChecked); mPickUpPreference.setEnabled(isChecked); mHandwavePreference.setEnabled(isChecked); diff --git a/parts/src/org/lineageos/settings/doze/DozeUtils.java b/parts/src/org/lineageos/settings/doze/DozeUtils.java index 31814ac..043dab9 100644 --- a/parts/src/org/lineageos/settings/doze/DozeUtils.java +++ b/parts/src/org/lineageos/settings/doze/DozeUtils.java @@ -30,6 +30,8 @@ import android.provider.Settings; import android.util.Log; import androidx.preference.PreferenceManager; +import org.lineageos.settings.utils.FileUtils; + import static android.provider.Settings.Secure.DOZE_ALWAYS_ON; import static android.provider.Settings.Secure.DOZE_ENABLED; @@ -40,6 +42,7 @@ public final class DozeUtils { private static final String DOZE_INTENT = "com.android.systemui.doze.pulse"; protected static final String ALWAYS_ON_DISPLAY = "always_on_display"; + protected static final String DOZE_BRIGHTNESS_KEY = "doze_brightness"; protected static final String WAKE_ON_GESTURE_KEY = "wake_on_gesture"; protected static final String CATEG_PICKUP_SENSOR = "pickup_sensor"; protected static final String CATEG_PROX_SENSOR = "proximity_sensor"; @@ -48,6 +51,19 @@ public final class DozeUtils { protected static final String GESTURE_HAND_WAVE_KEY = "gesture_hand_wave"; protected static final String GESTURE_POCKET_KEY = "gesture_pocket"; + private static final String DOZE_MODE_PATH = + "/sys/devices/platform/soc/soc:qcom,dsi-display/doze_mode"; + protected static final String DOZE_MODE_HBM = "1"; + protected static final String DOZE_MODE_LBM = "0"; + + protected static final String DOZE_BRIGHTNESS_LBM = "0"; + protected static final String DOZE_BRIGHTNESS_HBM = "1"; + protected static final String DOZE_BRIGHTNESS_AUTO = "2"; + + public static void onBootCompleted(Context context) { + checkDozeService(context); + restoreDozeModes(context); + } public static void startService(Context context) { if (DEBUG) Log.d(TAG, "Starting service"); @@ -61,13 +77,21 @@ public final class DozeUtils { } public static void checkDozeService(Context context) { - if (isDozeEnabled(context) && !isAlwaysOnEnabled(context) && sensorsEnabled(context)) { + if (isDozeEnabled(context) + && (!isAlwaysOnEnabled(context) || isDozeAutoBrightnessEnabled(context)) + && sensorsEnabled(context)) { startService(context); } else { stopService(context); } } + private static void restoreDozeModes(Context context) { + if (isAlwaysOnEnabled(context) && !isDozeAutoBrightnessEnabled(context)) { + setDozeMode(PreferenceManager.getDefaultSharedPreferences(context).getString( + DOZE_BRIGHTNESS_KEY, String.valueOf(DOZE_BRIGHTNESS_LBM))); + } + } protected static boolean getProxCheckBeforePulse(Context context) { try { Context con = context.createPackageContext("com.android.systemui", 0); @@ -118,6 +142,16 @@ public final class DozeUtils { return new AmbientDisplayConfiguration(context).alwaysOnAvailable(); } + protected static boolean setDozeMode(String value) { + return FileUtils.writeLine(DOZE_MODE_PATH, value); + } + + protected static boolean isDozeAutoBrightnessEnabled(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context) + .getString(DOZE_BRIGHTNESS_KEY, DOZE_BRIGHTNESS_LBM) + .equals(DOZE_BRIGHTNESS_AUTO); + } + protected static boolean isGestureEnabled(Context context, String gesture) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(gesture, false); } @@ -139,8 +173,8 @@ public final class DozeUtils { } public static boolean sensorsEnabled(Context context) { - return isPickUpEnabled(context) || isHandwaveGestureEnabled(context) - || isPocketGestureEnabled(context); + return isDozeAutoBrightnessEnabled(context) || isHandwaveGestureEnabled(context) + || isPickUpEnabled(context) || isPocketGestureEnabled(context); } protected static Sensor getSensor(SensorManager sm, String type) { diff --git a/rootdir/etc/init.target.rc b/rootdir/etc/init.target.rc index daa0259..8b985ed 100644 --- a/rootdir/etc/init.target.rc +++ b/rootdir/etc/init.target.rc @@ -80,6 +80,10 @@ on boot chown system system /sys/class/thermal/thermal_message/sconfig write /sys/class/thermal/thermal_message/sconfig 10 + # Set doze mode permissions + chown system system /sys/devices/platform/soc/soc:qcom,dsi-display/doze_mode + chmod 0660 /sys/devices/platform/soc/soc:qcom,dsi-display/doze_mode + on property:sys.boot_completed=1 # Set allocstall_threshold to 0 # Set swappiness to 100 diff --git a/sepolicy/vendor/file_contexts b/sepolicy/vendor/file_contexts index a8a6020..35899bc 100644 --- a/sepolicy/vendor/file_contexts +++ b/sepolicy/vendor/file_contexts @@ -8,6 +8,7 @@ /sys/devices/platform/soc/[a-f0-9]+.qcom,mdss_mdp/drm/card([0-3])+/card([0-3])+-DSI-1/panel_info u:object_r:vendor_sysfs_graphics:s0 /sys/devices/platform/soc/soc:qcom,dsi-display/dc_enable u:object_r:sysfs_anti_flicker:s0 /sys/devices/platform/soc/soc:qcom,dsi-display/hbm u:object_r:sysfs_hbm:s0 +/sys/devices/platform/soc/soc:qcom,dsi-display/doze_mode u:object_r:sysfs_doze:s0 # Fingerprint /dev/goodix_fp u:object_r:fingerprint_device:s0 diff --git a/sepolicy/vendor/system_app.te b/sepolicy/vendor/system_app.te new file mode 100644 index 0000000..34ef8e5 --- /dev/null +++ b/sepolicy/vendor/system_app.te @@ -0,0 +1,3 @@ +type sysfs_doze, sysfs_type, fs_type; + +allow system_app sysfs_doze:file rw_file_perms;