diff --git a/res/values/cherish_arrays.xml b/res/values/cherish_arrays.xml index 66bcdf5..7001fa9 100644 --- a/res/values/cherish_arrays.xml +++ b/res/values/cherish_arrays.xml @@ -1373,4 +1373,21 @@ 3 4 + + + + @string/night_display_auto_mode_never + @string/night_display_auto_mode_twilight + @string/sleep_mode_schedule_mixed_sunset + @string/sleep_mode_schedule_mixed_sunrise + @string/night_display_auto_mode_custom + + + 0 + 1 + 3 + 4 + 2 + + diff --git a/res/values/cherish_strings.xml b/res/values/cherish_strings.xml index 4817470..2ef8191 100644 --- a/res/values/cherish_strings.xml +++ b/res/values/cherish_strings.xml @@ -1341,4 +1341,27 @@ Radio info + + Sleep Mode + Sunset + Sunrise + Turns on from sunset to a custom time + Turns on from a custom time to sunrise + Toggles + Turn off Wi-Fi + Disable Wi-Fi when Sleep mode is turned on + Turn off Bluetooth + Disable Bluetooth when Sleep mode is turned on + Turn off Mobile data + Disable Mobile data when Sleep mode is turned on + Turn off Location + Disable Location when Sleep mode is turned on + Turn off Sensors + Disable Sensors when Sleep mode is turned on + Turn off AOD + Disable Always on display when Sleep mode is turned on + Turn on Aggressive Battery + Enable Aggressive idle and standby when Sleep mode is turned on + Sleep mode allows you to disable certain services to help save battery and silence your phone while you sleep. + diff --git a/res/xml/sleep_mode_settings.xml b/res/xml/sleep_mode_settings.xml new file mode 100644 index 0000000..e227254 --- /dev/null +++ b/res/xml/sleep_mode_settings.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/cherish/settings/fragments/SensorBlockSettings.java b/src/com/cherish/settings/fragments/SensorBlockSettings.java index c529c9a..df0860c 100644 --- a/src/com/cherish/settings/fragments/SensorBlockSettings.java +++ b/src/com/cherish/settings/fragments/SensorBlockSettings.java @@ -30,6 +30,7 @@ import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; +import android.text.format.DateFormat; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -60,6 +61,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.time.format.DateTimeFormatter; +import java.time.LocalTime; + @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) public class SensorBlockSettings extends SettingsPreferenceFragment implements Preference.OnPreferenceClickListener { @@ -72,6 +76,7 @@ public class SensorBlockSettings extends SettingsPreferenceFragment private PackageManager mPackageManager; private PreferenceGroup mSensorBlockPrefList; private Preference mAddSensorBlockPref; + private Preference mSleepMode; private String mBlockedPackageList; private Map mBlockedPackages; @@ -100,12 +105,78 @@ public class SensorBlockSettings extends SettingsPreferenceFragment mAddSensorBlockPref.setOnPreferenceClickListener(this); mContext = getActivity().getApplicationContext(); + + mSleepMode = findPreference("sleep_mode"); + updateSleepModeSummary(); + } + + private void updateSleepModeSummary() { + if (mSleepMode == null) return; + boolean enabled = Settings.Secure.getIntForUser(getActivity().getContentResolver(), + Settings.Secure.SLEEP_MODE_ENABLED, 0, UserHandle.USER_CURRENT) == 1; + int mode = Settings.Secure.getIntForUser(getActivity().getContentResolver(), + Settings.Secure.SLEEP_MODE_AUTO_MODE, 0, UserHandle.USER_CURRENT); + String timeValue = Settings.Secure.getStringForUser(getActivity().getContentResolver(), + Settings.Secure.SLEEP_MODE_AUTO_TIME, UserHandle.USER_CURRENT); + if (timeValue == null || timeValue.equals("")) timeValue = "20:00,07:00"; + String[] time = timeValue.split(",", 0); + String outputFormat = DateFormat.is24HourFormat(getContext()) ? "HH:mm" : "h:mm a"; + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputFormat); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + LocalTime sinceValue = LocalTime.parse(time[0], formatter); + LocalTime tillValue = LocalTime.parse(time[1], formatter); + String detail; + switch (mode) { + default: + case 0: + detail = getActivity().getString(enabled + ? R.string.night_display_summary_on_auto_mode_never + : R.string.night_display_summary_off_auto_mode_never); + break; + case 1: + detail = getActivity().getString(enabled + ? R.string.night_display_summary_on_auto_mode_twilight + : R.string.night_display_summary_off_auto_mode_twilight); + break; + case 2: + if (enabled) { + detail = getActivity().getString(R.string.night_display_summary_on_auto_mode_custom, tillValue.format(outputFormatter)); + } else { + detail = getActivity().getString(R.string.night_display_summary_off_auto_mode_custom, sinceValue.format(outputFormatter)); + } + break; + case 3: + if (enabled) { + detail = getActivity().getString(R.string.night_display_summary_on_auto_mode_custom, tillValue.format(outputFormatter)); + } else { + detail = getActivity().getString(R.string.night_display_summary_off_auto_mode_twilight); + } + break; + case 4: + if (enabled) { + detail = getActivity().getString(R.string.night_display_summary_on_auto_mode_twilight); + } else { + detail = getActivity().getString(R.string.night_display_summary_off_auto_mode_custom, sinceValue.format(outputFormatter)); + } + break; + } + String summary = getActivity().getString(enabled + ? R.string.night_display_summary_on + : R.string.night_display_summary_off, detail); + mSleepMode.setSummary(summary); } @Override public void onResume() { super.onResume(); refreshCustomApplicationPrefs(); + updateSleepModeSummary(); + } + + @Override + public void onPause() { + super.onPause(); + updateSleepModeSummary(); } @Override diff --git a/src/com/cherish/settings/fragments/SleepMode.java b/src/com/cherish/settings/fragments/SleepMode.java new file mode 100644 index 0000000..e32958c --- /dev/null +++ b/src/com/cherish/settings/fragments/SleepMode.java @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2021 Havoc-OS + * + * 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.cherish.settings.fragments; + +import android.app.TimePickerDialog; +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.os.Bundle; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.format.DateFormat; +import android.view.View; +import android.widget.Button; +import android.widget.TimePicker; + +import androidx.preference.DropDownPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settingslib.widget.LayoutPreference; + +import java.time.format.DateTimeFormatter; +import java.time.LocalTime; + +public class SleepMode extends SettingsPreferenceFragment implements + Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener { + + private static final String MODE_KEY = "sleep_mode_auto_mode"; + private static final String SINCE_PREF_KEY = "sleep_mode_auto_since"; + private static final String TILL_PREF_KEY = "sleep_mode_auto_till"; + private static final String KEY_SLEEP_BUTTON = "sleep_mode_button"; + private static final String TOGGLES_CATEGORY_KEY = "sleep_mode_toggles"; + + private PreferenceCategory mToggles; + private DropDownPreference mModePref; + private Preference mSincePref; + private Preference mTillPref; + private Button mTurnOnButton; + private Button mTurnOffButton; + private Context mContext; + private Handler mHandler; + private ContentResolver mContentResolver; + private boolean mIsNavSwitchingMode = false; + + private final View.OnClickListener mButtonListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v == mTurnOnButton || v == mTurnOffButton) { + boolean enabled = Settings.Secure.getIntForUser(mContentResolver, + Settings.Secure.SLEEP_MODE_ENABLED, 0, UserHandle.USER_CURRENT) == 1; + enableSleepMode(!enabled); + updateStateInternal(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mIsNavSwitchingMode = false; + } + }, 1500); + } + } + }; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + addPreferencesFromResource(R.xml.sleep_mode_settings); + PreferenceScreen screen = getPreferenceScreen(); + + mContext = getContext(); + mHandler = new Handler(); + mContentResolver = getActivity().getContentResolver(); + + SettingsObserver settingsObserver = new SettingsObserver(new Handler()); + settingsObserver.observe(); + + mSincePref = findPreference(SINCE_PREF_KEY); + mSincePref.setOnPreferenceClickListener(this); + mTillPref = findPreference(TILL_PREF_KEY); + mTillPref.setOnPreferenceClickListener(this); + + int mode = Settings.Secure.getIntForUser(mContentResolver, + MODE_KEY, 0, UserHandle.USER_CURRENT); + mModePref = (DropDownPreference) findPreference(MODE_KEY); + mModePref.setValue(String.valueOf(mode)); + mModePref.setSummary(mModePref.getEntry()); + mModePref.setOnPreferenceChangeListener(this); + + mToggles = findPreference(TOGGLES_CATEGORY_KEY); + + LayoutPreference preference = findPreference(KEY_SLEEP_BUTTON); + mTurnOnButton = preference.findViewById(R.id.sleep_mode_on_button); + mTurnOnButton.setOnClickListener(mButtonListener); + mTurnOffButton = preference.findViewById(R.id.sleep_mode_off_button); + mTurnOffButton.setOnClickListener(mButtonListener); + + updateTimeEnablement(mode); + updateTimeSummary(mode); + updateStateInternal(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object objValue) { + if (preference == mModePref) { + int value = Integer.parseInt((String) objValue); + int index = mModePref.findIndexOfValue((String) objValue); + mModePref.setSummary(mModePref.getEntries()[index]); + Settings.Secure.putIntForUser(mContentResolver, + MODE_KEY, value, UserHandle.USER_CURRENT); + updateTimeEnablement(value); + updateTimeSummary(value); + updateStateInternal(); + return true; + } + return false; + } + + @Override + public boolean onPreferenceClick(Preference preference) { + if (preference == mSincePref || preference == mTillPref) { + String[] times = getCustomTimeSetting(); + boolean isSince = preference == mSincePref; + int hour, minute; + TimePickerDialog.OnTimeSetListener listener = (view, hourOfDay, minute1) -> { + updateTimeSetting(isSince, hourOfDay, minute1); + }; + if (isSince) { + String[] sinceValues = times[0].split(":", 0); + hour = Integer.parseInt(sinceValues[0]); + minute = Integer.parseInt(sinceValues[1]); + } else { + String[] tillValues = times[1].split(":", 0); + hour = Integer.parseInt(tillValues[0]); + minute = Integer.parseInt(tillValues[1]); + } + TimePickerDialog dialog = new TimePickerDialog(mContext, listener, + hour, minute, DateFormat.is24HourFormat(mContext)); + dialog.show(); + return true; + } + return false; + } + + private String[] getCustomTimeSetting() { + String value = Settings.Secure.getStringForUser(mContentResolver, + Settings.Secure.SLEEP_MODE_AUTO_TIME, UserHandle.USER_CURRENT); + if (value == null || value.equals("")) value = "20:00,07:00"; + return value.split(",", 0); + } + + private void updateTimeEnablement(int mode) { + mSincePref.setVisible(mode == 2 || mode == 4); + mTillPref.setVisible(mode == 2 || mode == 3); + } + + private void updateTimeSummary(int mode) { + updateTimeSummary(getCustomTimeSetting(), mode); + } + + private void updateTimeSummary(String[] times, int mode) { + if (mode == 0) { + mSincePref.setSummary("-"); + mTillPref.setSummary("-"); + return; + } + + if (mode == 1) { + mSincePref.setSummary(R.string.sleep_mode_schedule_sunset); + mTillPref.setSummary(R.string.sleep_mode_schedule_sunrise); + return; + } + + String outputFormat = DateFormat.is24HourFormat(mContext) ? "HH:mm" : "h:mm a"; + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputFormat); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + LocalTime sinceDT = LocalTime.parse(times[0], formatter); + LocalTime tillDT = LocalTime.parse(times[1], formatter); + + if (mode == 3) { + mSincePref.setSummary(R.string.sleep_mode_schedule_sunset); + mTillPref.setSummary(tillDT.format(outputFormatter)); + } else if (mode == 4) { + mTillPref.setSummary(R.string.sleep_mode_schedule_sunrise); + mSincePref.setSummary(sinceDT.format(outputFormatter)); + } else { + mSincePref.setSummary(sinceDT.format(outputFormatter)); + mTillPref.setSummary(tillDT.format(outputFormatter)); + } + } + + private void updateTimeSetting(boolean since, int hour, int minute) { + String[] times = getCustomTimeSetting(); + String nHour = ""; + String nMinute = ""; + if (hour < 10) nHour += "0"; + if (minute < 10) nMinute += "0"; + nHour += String.valueOf(hour); + nMinute += String.valueOf(minute); + times[since ? 0 : 1] = nHour + ":" + nMinute; + Settings.Secure.putStringForUser(mContentResolver, + Settings.Secure.SLEEP_MODE_AUTO_TIME, + times[0] + "," + times[1], UserHandle.USER_CURRENT); + updateTimeSummary(times, Integer.parseInt(mModePref.getValue())); + } + + private void updateStateInternal() { + if (mTurnOnButton == null || mTurnOffButton == null) { + return; + } + + int mode = Settings.Secure.getIntForUser(mContentResolver, + MODE_KEY, 0, UserHandle.USER_CURRENT); + boolean isActivated = Settings.Secure.getIntForUser(mContentResolver, + Settings.Secure.SLEEP_MODE_ENABLED, 0, UserHandle.USER_CURRENT) == 1; + String timeValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_AUTO_TIME, UserHandle.USER_CURRENT); + if (timeValue == null || timeValue.equals("")) timeValue = "20:00,07:00"; + String[] time = timeValue.split(",", 0); + String outputFormat = DateFormat.is24HourFormat(mContext) ? "HH:mm" : "h:mm a"; + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputFormat); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + LocalTime sinceValue = LocalTime.parse(time[0], formatter); + LocalTime tillValue = LocalTime.parse(time[1], formatter); + + String buttonText; + + switch (mode) { + default: + case 0: + buttonText = mContext.getString(isActivated ? R.string.night_display_activation_off_manual + : R.string.night_display_activation_on_manual); + break; + case 1: + buttonText = mContext.getString(isActivated ? R.string.night_display_activation_off_twilight + : R.string.night_display_activation_on_twilight); + break; + case 2: + if (isActivated) { + buttonText = mContext.getString(R.string.night_display_activation_off_custom, sinceValue.format(outputFormatter)); + } else { + buttonText = mContext.getString(R.string.night_display_activation_on_custom, tillValue.format(outputFormatter)); + } + break; + case 3: + if (isActivated) { + buttonText = mContext.getString(R.string.night_display_activation_off_twilight); + } else { + buttonText = mContext.getString(R.string.night_display_activation_on_custom, tillValue.format(outputFormatter)); + } + break; + case 4: + if (isActivated) { + buttonText = mContext.getString(R.string.night_display_activation_off_custom, sinceValue.format(outputFormatter)); + } else { + buttonText = mContext.getString(R.string.night_display_activation_on_twilight); + } + break; + } + + if (isActivated) { + mTurnOnButton.setVisibility(View.GONE); + mTurnOffButton.setVisibility(View.VISIBLE); + mTurnOffButton.setText(buttonText); + mToggles.setEnabled(false); + } else { + mTurnOnButton.setVisibility(View.VISIBLE); + mTurnOffButton.setVisibility(View.GONE); + mTurnOnButton.setText(buttonText); + mToggles.setEnabled(true); + } + } + + private void enableSleepMode(boolean enable) { + if (mIsNavSwitchingMode) return; + mIsNavSwitchingMode = true; + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_ENABLED, enable ? 1 : 0, UserHandle.USER_CURRENT); + } + + private class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + } + + void observe() { + ContentResolver resolver = mContentResolver; + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SLEEP_MODE_ENABLED), false, this, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SLEEP_MODE_AUTO_MODE), false, this, + UserHandle.USER_ALL); + } + + @Override + public void onChange(boolean selfChange) { + updateStateInternal(); + } + } + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.CHERISH_SETTINGS; + } +} diff --git a/src/com/cherish/settings/fragments/SleepModeReceiver.java b/src/com/cherish/settings/fragments/SleepModeReceiver.java new file mode 100644 index 0000000..314494f --- /dev/null +++ b/src/com/cherish/settings/fragments/SleepModeReceiver.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Havoc-OS + * + * 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.cherish.settings.fragments; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.provider.Settings; + +import com.android.internal.util.custom.SleepModeController; + +public class SleepModeReceiver extends BroadcastReceiver { + + private static final String TAG = "SleepModeReceiver"; + + public SleepModeReceiver() { + } + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction() != null && + intent.getAction().equals(SleepModeController.SLEEP_MODE_TURN_OFF)) { + Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.SLEEP_MODE_ENABLED, 0); + } + } +}