diff --git a/parts/AndroidManifest.xml b/parts/AndroidManifest.xml index adb5814..4e77b67 100644 --- a/parts/AndroidManifest.xml +++ b/parts/AndroidManifest.xml @@ -1,7 +1,7 @@ + Black Shark settings + Additional device specific tweaks + + + Rear LED + Mode + Enabled + Change the behaviour of rear LED logo + Breathing RGB + Manual + Red + Green + Blue + + + Speaker tweaks + Enable built-in EQ or game mode + Enabled + Equalizer + 256 Hz + 512 Hz + 1024 Hz + 2048 Hz + 4096 Hz + Game mode + Disabled + Default + Shooter + If game mode is enabled, EQ will not be working. To apply changes immediately, you can restart playback, if something was playing. + Thermal profiles Adjust per-app thermal profiles for optimum performance diff --git a/parts/res/xml/logo.xml b/parts/res/xml/logo.xml new file mode 100644 index 0000000..196df33 --- /dev/null +++ b/parts/res/xml/logo.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + diff --git a/parts/res/xml/sharkparts.xml b/parts/res/xml/sharkparts.xml new file mode 100644 index 0000000..5f582f7 --- /dev/null +++ b/parts/res/xml/sharkparts.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/parts/res/xml/shortcuts.xml b/parts/res/xml/shortcuts.xml new file mode 100644 index 0000000..0042b55 --- /dev/null +++ b/parts/res/xml/shortcuts.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/parts/res/xml/speaker.xml b/parts/res/xml/speaker.xml new file mode 100644 index 0000000..f204f73 --- /dev/null +++ b/parts/res/xml/speaker.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/parts/src/org/lineageos/settings/BootCompletedReceiver.java b/parts/src/org/lineageos/settings/BootCompletedReceiver.java index 0728d09..f350cf7 100644 --- a/parts/src/org/lineageos/settings/BootCompletedReceiver.java +++ b/parts/src/org/lineageos/settings/BootCompletedReceiver.java @@ -20,12 +20,20 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import android.util.Log; import org.lineageos.settings.dirac.DiracUtils; import org.lineageos.settings.doze.DozeUtils; import org.lineageos.settings.thermal.ThermalUtils; +import org.lineageos.settings.logo.LogoFragment; +import org.lineageos.settings.utils.SettingsUtils; + +import org.lineageos.settings.logo.LogoUtil; +import org.lineageos.settings.speaker.SpeakerUtil; + public class BootCompletedReceiver extends BroadcastReceiver { private static final boolean DEBUG = false; @@ -37,5 +45,23 @@ public void onReceive(final Context context, Intent intent) { DiracUtils.initialize(); DozeUtils.checkDozeService(context); ThermalUtils.startService(context); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + int intValue = Integer.parseInt(sharedPreferences.getString(LogoFragment.KEY_LOGO_MODE, String.valueOf(LogoFragment.LOGO_MODE_BREATH))); + + if (SettingsUtils.getEnabled(context, LogoFragment.KEY_LOGO_ENABLE)) { + if (intValue == LogoFragment.LOGO_MODE_BREATH) { + LogoUtil.enableBreathingEffect(); + } else if (intValue == LogoFragment.LOGO_MODE_MANUAL) { + final int r = SettingsUtils.getInt(context, LogoFragment.KEY_LOGO_MODE_MANUAL_RED, 1); + final int g = SettingsUtils.getInt(context, LogoFragment.KEY_LOGO_MODE_MANUAL_GREEN, 1); + final int b = SettingsUtils.getInt(context, LogoFragment.KEY_LOGO_MODE_MANUAL_BLUE, 1); + LogoUtil.setRGBStill(r, g, b); + } + } else { + LogoUtil.turnOff(); + } + + SpeakerUtil.initInjector(context); } } diff --git a/parts/src/org/lineageos/settings/KeyHandler.java b/parts/src/org/lineageos/settings/KeyHandler.java new file mode 100644 index 0000000..ebd6300 --- /dev/null +++ b/parts/src/org/lineageos/settings/KeyHandler.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 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; + +import android.app.NotificationManager; +import android.content.Context; +import android.os.VibrationEffect; +import android.os.Vibrator; +import android.view.KeyEvent; +import android.util.Log; + +import com.android.internal.os.DeviceKeyHandler; + +public class KeyHandler implements DeviceKeyHandler { + private static final String TAG = KeyHandler.class.getSimpleName(); + + private static final int KEY_SLIDER_OFF = 250; + private static final int KEY_SLIDER_ON = 251; + + private final Context mContext; + private final NotificationManager mNotificationManager; + private final Vibrator mVibrator; + + public KeyHandler(Context context) { + mContext = context; + + mNotificationManager = mContext.getSystemService(NotificationManager.class); + mVibrator = mContext.getSystemService(Vibrator.class); + } + + public KeyEvent handleKeyEvent(KeyEvent event) { + int scanCode = event.getScanCode(); + + switch(scanCode) { + case KEY_SLIDER_OFF: + mNotificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); + mNotificationManager.setNotificationPolicy( + new NotificationManager.Policy( + NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA + | NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0 + ) + ); + break; + case KEY_SLIDER_ON: + mNotificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL); + break; + default: + return event; + } + + doHapticFeedback(); + + return null; + } + + private void doHapticFeedback() { + if (mVibrator != null && mVibrator.hasVibrator()) { + mVibrator.vibrate(VibrationEffect.createOneShot(50, + VibrationEffect.DEFAULT_AMPLITUDE)); + } + } +} diff --git a/parts/src/org/lineageos/settings/SharkParts.java b/parts/src/org/lineageos/settings/SharkParts.java new file mode 100644 index 0000000..c8ec6d2 --- /dev/null +++ b/parts/src/org/lineageos/settings/SharkParts.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 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; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.MenuItem; +import android.content.Intent; +import android.os.Bundle; +import androidx.preference.PreferenceFragment; +import androidx.preference.Preference; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import androidx.preference.TwoStatePreference; +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; + +import org.lineageos.settings.logo.LogoActivity; +import org.lineageos.settings.speaker.SpeakerActivity; + +public class SharkParts extends CollapsingToolbarBaseActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Fragment fragment = getFragmentManager().findFragmentById(com.android.settingslib.collapsingtoolbar.R.id.content_frame); + SharkPartsFragment mSharkPartsFragment; + if (fragment == null) { + mSharkPartsFragment = new SharkPartsFragment(); + getFragmentManager().beginTransaction() + .add(com.android.settingslib.collapsingtoolbar.R.id.content_frame, mSharkPartsFragment) + .commit(); + } + } + + public static class SharkPartsFragment extends PreferenceFragment implements + Preference.OnPreferenceChangeListener { + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.sharkparts, rootKey); + Preference mLogoPref = findPreference("logo"); + mLogoPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(getContext(), LogoActivity.class); + startActivity(intent); + return true; + } + }); + + Preference mSpeakerPref = findPreference("speaker"); + mSpeakerPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(getContext(), SpeakerActivity.class); + startActivity(intent); + return true; + } + }); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final String key = preference.getKey(); + return true; + } + } +} diff --git a/parts/src/org/lineageos/settings/logo/LogoActivity.java b/parts/src/org/lineageos/settings/logo/LogoActivity.java new file mode 100644 index 0000000..0d5bb28 --- /dev/null +++ b/parts/src/org/lineageos/settings/logo/LogoActivity.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020-2023 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.logo; + +import android.os.Bundle; + +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; + +public class LogoActivity extends CollapsingToolbarBaseActivity { + + private static final String TAG_LOGO = "logo"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getFragmentManager().beginTransaction() + .replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame, new LogoFragment(), TAG_LOGO) + .commit(); + } +} diff --git a/parts/src/org/lineageos/settings/logo/LogoFragment.java b/parts/src/org/lineageos/settings/logo/LogoFragment.java new file mode 100644 index 0000000..fdae127 --- /dev/null +++ b/parts/src/org/lineageos/settings/logo/LogoFragment.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2020 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.logo; + +import android.content.res.Resources; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Parcel; +import android.os.RemoteException; +import android.preference.PreferenceManager; +import android.provider.Settings; +import android.widget.CompoundButton; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragment; +import androidx.preference.SwitchPreference; +import androidx.preference.SeekBarPreference; +import androidx.preference.ListPreference; + +import com.android.settingslib.widget.MainSwitchPreference; + +import org.lineageos.settings.R; + +import org.lineageos.settings.utils.SettingsUtils; + +import org.lineageos.settings.logo.LogoUtil; + +public class LogoFragment extends PreferenceFragment implements + Preference.OnPreferenceChangeListener, CompoundButton.OnCheckedChangeListener, + SharedPreferences.OnSharedPreferenceChangeListener { + public static final String KEY_LOGO_ENABLE = "logo_control_enable"; + public static final String KEY_LOGO_MODE = "logo_control_mode"; + public static final String KEY_LOGO_MODE_MANUAL_RED = "logo_control_manual_red"; + public static final String KEY_LOGO_MODE_MANUAL_GREEN = "logo_control_manual_green"; + public static final String KEY_LOGO_MODE_MANUAL_BLUE = "logo_control_manual_blue"; + public static final String KEY_LOGO_MODE_BREATH = "logo_control_breath"; + + public static final int LOGO_MODE_BREATH = 1; + public static final int LOGO_MODE_MANUAL = 2; + private static final int LOGO_DISABLED_VALUE = 0; + private static final int LOGO_MIN_VALUE = 1; + private static final int LOGO_MAX_VALUE = 255; + + private MainSwitchPreference mSwitchBar; + private ListPreference mLogoControlMode; + private SeekBarPreference mLogoManualBarRed; + private SeekBarPreference mLogoManualBarGreen; + private SeekBarPreference mLogoManualBarBlue; + + private void setSlidersVisibility(boolean state) { + mLogoManualBarRed.setVisible(state); + mLogoManualBarGreen.setVisible(state); + mLogoManualBarBlue.setVisible(state); + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.logo); + + mSwitchBar = (MainSwitchPreference) findPreference(KEY_LOGO_ENABLE); + mSwitchBar.setChecked(SettingsUtils.getEnabled(getActivity(), KEY_LOGO_ENABLE)); + mSwitchBar.addOnSwitchChangeListener(this); + + mLogoControlMode = (ListPreference) findPreference(KEY_LOGO_MODE); + + mLogoManualBarRed = (SeekBarPreference) findPreference(KEY_LOGO_MODE_MANUAL_RED); + mLogoManualBarRed.setValue(SettingsUtils.getInt(getActivity(), KEY_LOGO_MODE_MANUAL_RED, 1)); + mLogoManualBarGreen = (SeekBarPreference) findPreference(KEY_LOGO_MODE_MANUAL_GREEN); + mLogoManualBarGreen.setValue(SettingsUtils.getInt(getActivity(), KEY_LOGO_MODE_MANUAL_GREEN, 1)); + mLogoManualBarBlue = (SeekBarPreference) findPreference(KEY_LOGO_MODE_MANUAL_BLUE); + mLogoManualBarBlue.setValue(SettingsUtils.getInt(getActivity(), KEY_LOGO_MODE_MANUAL_BLUE, 1)); + + mLogoManualBarRed.setOnPreferenceChangeListener(this); + mLogoManualBarGreen.setOnPreferenceChangeListener(this); + mLogoManualBarBlue.setOnPreferenceChangeListener(this); + + if (mLogoControlMode.getValue() == null) { + mLogoControlMode.setValue("1"); + } + + final int mode = Integer.parseInt((String) mLogoControlMode.getValue()); + if (mode == LOGO_MODE_BREATH) { + mLogoControlMode.setSummary(getResources().getString(R.string.logo_control_breath_title)); + setSlidersVisibility(false); + } else if (mode == LOGO_MODE_MANUAL) { + mLogoControlMode.setSummary(getResources().getString(R.string.logo_control_manual_title)); + setSlidersVisibility(true); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + sharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onResume() { + super.onResume(); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + sharedPreferences.registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean enabled) { + SettingsUtils.setEnabled(getActivity(), KEY_LOGO_ENABLE, enabled); + + LogoUtil.turnOff(); + if (!enabled) return; + + int mode = Integer.parseInt((String) mLogoControlMode.getValue()); + if (mode == LOGO_MODE_BREATH) { + enableBreathingMode(); + } else if (mode == LOGO_MODE_MANUAL) { + enableManualMode(); + } + } + + private void enableManualMode() { + mLogoControlMode.setSummary(getResources().getString(R.string.logo_control_manual_title)); + setSlidersVisibility(true); + + final int r = SettingsUtils.getInt(getActivity(), KEY_LOGO_MODE_MANUAL_RED, 1); + final int g = SettingsUtils.getInt(getActivity(), KEY_LOGO_MODE_MANUAL_GREEN, 1); + final int b = SettingsUtils.getInt(getActivity(), KEY_LOGO_MODE_MANUAL_BLUE, 1); + LogoUtil.setRGBStill(r, g, b); + } + + private void enableBreathingMode() { + mLogoControlMode.setSummary(getResources().getString(R.string.logo_control_breath_title)); + setSlidersVisibility(false); + LogoUtil.enableBreathingEffect(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object value) { + final String key = preference.getKey(); + if (KEY_LOGO_MODE_MANUAL_RED.equals(key)) { + final int r = (Integer)value; + SettingsUtils.putInt(getActivity(), KEY_LOGO_MODE_MANUAL_RED, r); + LogoUtil.setStillRed(r); + } else if (KEY_LOGO_MODE_MANUAL_GREEN.equals(key)) { + final int g = (Integer)value; + SettingsUtils.putInt(getActivity(), KEY_LOGO_MODE_MANUAL_GREEN, g); + LogoUtil.setStillGreen(g); + } else if (KEY_LOGO_MODE_MANUAL_BLUE.equals(key)) { + final int b = (Integer)value; + SettingsUtils.putInt(getActivity(), KEY_LOGO_MODE_MANUAL_BLUE, b); + LogoUtil.setStillBlue(b); + } + return true; + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (!KEY_LOGO_MODE.equals(key)) return; + int mode = Integer.parseInt(sharedPreferences.getString(key, String.valueOf(LOGO_MODE_BREATH))); + mLogoControlMode.setValue(String.valueOf(mode)); + + // Reset everything before switching mode + LogoUtil.turnOff(); + + if (mode == LOGO_MODE_BREATH) { + enableBreathingMode(); + } else if (mode == LOGO_MODE_MANUAL) { + enableManualMode(); + } + } +} diff --git a/parts/src/org/lineageos/settings/logo/LogoUtil.java b/parts/src/org/lineageos/settings/logo/LogoUtil.java new file mode 100644 index 0000000..9a4d3e2 --- /dev/null +++ b/parts/src/org/lineageos/settings/logo/LogoUtil.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 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.logo; + +import org.lineageos.settings.utils.FileUtils; +import android.os.Handler; + +public class LogoUtil { + public static final String RED_LED = "/sys/rgb/leds/green_1/brightness"; + public static final String GREEN_LED = "/sys/rgb/leds/red_1/brightness"; + public static final String BLUE_LED = "/sys/rgb/leds/blue_1/brightness"; + + public static final String RED_LED_BLINK = "/sys/rgb/leds/green_1/blink"; + public static final String GREEN_LED_BLINK = "/sys/rgb/leds/red_1/blink"; + public static final String BLUE_LED_BLINK = "/sys/rgb/leds/blue_1/blink"; + + public static void turnOff() { + FileUtils.writeLine(RED_LED_BLINK, "0"); + FileUtils.writeLine(GREEN_LED_BLINK, "0"); + FileUtils.writeLine(BLUE_LED_BLINK, "0"); + FileUtils.writeLine(RED_LED, "0"); + FileUtils.writeLine(GREEN_LED, "0"); + FileUtils.writeLine(BLUE_LED, "0"); + } + + public static void setRGBStill(int r, int g, int b) { + FileUtils.writeLine(RED_LED, String.valueOf(r)); + FileUtils.writeLine(GREEN_LED, String.valueOf(g)); + FileUtils.writeLine(BLUE_LED, String.valueOf(b)); + } + + public static void setStillRed(int value) { + FileUtils.writeLine(RED_LED, String.valueOf(value)); + } + + public static void setStillGreen(int value) { + FileUtils.writeLine(GREEN_LED, String.valueOf(value)); + } + + public static void setStillBlue(int value) { + FileUtils.writeLine(BLUE_LED, String.valueOf(value)); + } + + public static void setBlinkRed(boolean state) { + FileUtils.writeLine(RED_LED_BLINK, state ? "1" : "0"); + } + + public static void setBlinkBlue(boolean state) { + FileUtils.writeLine(BLUE_LED_BLINK, state ? "1" : "0"); + } + + public static void setBlinkGreen(boolean state) { + FileUtils.writeLine(GREEN_LED_BLINK, state ? "1" : "0"); + } + + public static void enableBreathingEffect() { + final Handler handler = new Handler(); + setBlinkRed(true); + handler.postDelayed(new Runnable() { + @Override + public void run() { + setBlinkGreen(true); + } + }, 1000); + handler.postDelayed(new Runnable() { + @Override + public void run() { + setBlinkBlue(true); + } + }, 2000); + } +} diff --git a/parts/src/org/lineageos/settings/logo/QsService.java b/parts/src/org/lineageos/settings/logo/QsService.java new file mode 100644 index 0000000..237ec4c --- /dev/null +++ b/parts/src/org/lineageos/settings/logo/QsService.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2024 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.logo; + +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.os.Bundle; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.drawable.Icon; +import android.os.Build; +import android.service.quicksettings.Tile; +import android.service.quicksettings.TileService; + +import org.lineageos.settings.logo.LogoFragment; +import org.lineageos.settings.logo.LogoUtil; +import org.lineageos.settings.R; +import org.lineageos.settings.utils.SettingsUtils; + +public class QsService extends TileService { + private void updateState() { + final boolean enabled = SettingsUtils.getEnabled(getApplicationContext(), LogoFragment.KEY_LOGO_ENABLE); + getQsTile().setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); + getQsTile().setIcon(Icon.createWithResource(getApplicationContext(), R.drawable.logo)); + getQsTile().setLabel(getString(R.string.logo_control_title)); + getQsTile().updateTile(); + } + + @Override + public void onStartListening() { + super.onStartListening(); + updateState(); + } + + @Override + public void onClick() { + super.onClick(); + final Context context = getApplicationContext(); + + boolean enabled = !SettingsUtils.getEnabled(context, LogoFragment.KEY_LOGO_ENABLE); + SettingsUtils.setEnabled(context, LogoFragment.KEY_LOGO_ENABLE, enabled); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + int intValue = Integer.parseInt(sharedPreferences.getString(LogoFragment.KEY_LOGO_MODE, String.valueOf(LogoFragment.LOGO_MODE_BREATH))); + if (enabled) { + if (intValue == LogoFragment.LOGO_MODE_BREATH) { + LogoUtil.enableBreathingEffect(); + } else if (intValue == LogoFragment.LOGO_MODE_MANUAL) { + final int r = SettingsUtils.getInt(context, LogoFragment.KEY_LOGO_MODE_MANUAL_RED, 1); + final int g = SettingsUtils.getInt(context, LogoFragment.KEY_LOGO_MODE_MANUAL_GREEN, 1); + final int b = SettingsUtils.getInt(context, LogoFragment.KEY_LOGO_MODE_MANUAL_BLUE, 1); + LogoUtil.setRGBStill(r, g, b); + } + } else { + LogoUtil.turnOff(); + } + + updateState(); + } +} diff --git a/parts/src/org/lineageos/settings/speaker/SpeakerActivity.java b/parts/src/org/lineageos/settings/speaker/SpeakerActivity.java new file mode 100644 index 0000000..dd76fd7 --- /dev/null +++ b/parts/src/org/lineageos/settings/speaker/SpeakerActivity.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020-2023 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.speaker; + +import android.os.Bundle; + +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; + +public class SpeakerActivity extends CollapsingToolbarBaseActivity { + + private static final String TAG_SPEAKER = "speaker"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getFragmentManager().beginTransaction() + .replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame, new SpeakerFragment(), TAG_SPEAKER) + .commit(); + } +} diff --git a/parts/src/org/lineageos/settings/speaker/SpeakerFragment.java b/parts/src/org/lineageos/settings/speaker/SpeakerFragment.java new file mode 100644 index 0000000..2beb937 --- /dev/null +++ b/parts/src/org/lineageos/settings/speaker/SpeakerFragment.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2020 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.speaker; + +import android.content.res.Resources; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Parcel; +import android.os.RemoteException; +import android.preference.PreferenceManager; +import android.provider.Settings; +import android.widget.CompoundButton; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragment; +import androidx.preference.SwitchPreference; +import androidx.preference.SeekBarPreference; +import androidx.preference.ListPreference; + +import com.android.settingslib.widget.MainSwitchPreference; + +import org.lineageos.settings.R; + +import org.lineageos.settings.utils.SettingsUtils; + +import org.lineageos.settings.speaker.SpeakerUtil; + +public class SpeakerFragment extends PreferenceFragment implements + Preference.OnPreferenceChangeListener, CompoundButton.OnCheckedChangeListener, + SharedPreferences.OnSharedPreferenceChangeListener { + public static final String KEY_SPEAKER_TWEAKS_ENABLE = "speaker_tweaks_enable"; + public static final String KEY_SPEAKER_EQ_BASE = "speaker_control_eq_band_"; + public static final String KEY_SPEAKER_GAMEMODE = "speaker_gamemode_val"; + + public static final String EQ_DEFAULT = "3"; + public static final String GAMEMODE_DISABLED = "0"; + public static final String GAMEMODE_DEFAULT = "1"; + public static final String GAMEMODE_EATENCHICKEN = "2"; + + private MainSwitchPreference mSwitchBar; + private ListPreference mGameMode; + private SeekBarPreference mEqBand0; + private SeekBarPreference mEqBand1; + private SeekBarPreference mEqBand2; + private SeekBarPreference mEqBand3; + private SeekBarPreference mEqBand4; + + private void updateGameModeSummary() { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + final String val = sharedPreferences.getString(KEY_SPEAKER_GAMEMODE, GAMEMODE_DISABLED); + if (val.equals("0")) { + mGameMode.setSummary(R.string.speaker_control_gamemode_0); + } else if (val.equals("1")) { + mGameMode.setSummary(R.string.speaker_control_gamemode_1); + } else if (val.equals("2")) { + mGameMode.setSummary(R.string.speaker_control_gamemode_2); + } else { + mGameMode.setSummary(null); + } + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.speaker); + + mSwitchBar = (MainSwitchPreference) findPreference(KEY_SPEAKER_TWEAKS_ENABLE); + mSwitchBar.setChecked(SettingsUtils.getEnabled(getActivity(), KEY_SPEAKER_TWEAKS_ENABLE)); + mSwitchBar.addOnSwitchChangeListener(this); + + mGameMode = (ListPreference) findPreference(KEY_SPEAKER_GAMEMODE); + + mEqBand0 = (SeekBarPreference) findPreference(KEY_SPEAKER_EQ_BASE + "0"); + mEqBand1 = (SeekBarPreference) findPreference(KEY_SPEAKER_EQ_BASE + "1"); + mEqBand2 = (SeekBarPreference) findPreference(KEY_SPEAKER_EQ_BASE + "2"); + mEqBand3 = (SeekBarPreference) findPreference(KEY_SPEAKER_EQ_BASE + "3"); + mEqBand4 = (SeekBarPreference) findPreference(KEY_SPEAKER_EQ_BASE + "4"); + + mEqBand0.setValue(SettingsUtils.getInt(getActivity(), KEY_SPEAKER_EQ_BASE + "0", 3)); + mEqBand1.setValue(SettingsUtils.getInt(getActivity(), KEY_SPEAKER_EQ_BASE + "1", 3)); + mEqBand2.setValue(SettingsUtils.getInt(getActivity(), KEY_SPEAKER_EQ_BASE + "2", 3)); + mEqBand3.setValue(SettingsUtils.getInt(getActivity(), KEY_SPEAKER_EQ_BASE + "3", 3)); + mEqBand4.setValue(SettingsUtils.getInt(getActivity(), KEY_SPEAKER_EQ_BASE + "4", 3)); + + mEqBand0.setOnPreferenceChangeListener(this); + mEqBand1.setOnPreferenceChangeListener(this); + mEqBand2.setOnPreferenceChangeListener(this); + mEqBand3.setOnPreferenceChangeListener(this); + mEqBand4.setOnPreferenceChangeListener(this); + + if (mGameMode.getValue() == null) { + mGameMode.setValue(GAMEMODE_DISABLED); + } + + updateGameModeSummary(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + sharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onResume() { + super.onResume(); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + sharedPreferences.registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean enabled) { + SettingsUtils.setEnabled(getActivity(), KEY_SPEAKER_TWEAKS_ENABLE, enabled); + + SpeakerUtil.enabled = enabled; + SpeakerUtil.updateParameters(getActivity()); + updateGameModeSummary(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object value) { + final String key = preference.getKey(); + SettingsUtils.putInt(getActivity(), key, (Integer)value); + SpeakerUtil.updateParameters(getActivity()); + return true; + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (!KEY_SPEAKER_GAMEMODE.equals(key)) return; + String mode = sharedPreferences.getString(key, GAMEMODE_DISABLED); + mGameMode.setValue(mode); + updateGameModeSummary(); + SpeakerUtil.updateParameters(getActivity()); + } +} diff --git a/parts/src/org/lineageos/settings/speaker/SpeakerUtil.java b/parts/src/org/lineageos/settings/speaker/SpeakerUtil.java new file mode 100644 index 0000000..b8db1fd --- /dev/null +++ b/parts/src/org/lineageos/settings/speaker/SpeakerUtil.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020-2023 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.speaker; + +import android.content.Context; +import android.content.SharedPreferences; +import android.media.AudioManager; +import android.media.AudioPlaybackConfiguration; +import android.media.AudioDeviceInfo; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.util.Log; + +import java.lang.String; +import java.lang.StringBuilder; +import java.util.List; + +import org.lineageos.settings.speaker.SpeakerFragment; +import org.lineageos.settings.utils.SettingsUtils; + +public class SpeakerUtil { + private static final String TAG = "SpeakerUtil"; + private static final boolean DEBUG = false; + + private static AudioManager audioManager = null; + private static SharedPreferences sharedPreferences = null; + private static Handler handler = new Handler(); + + public static boolean enabled = false; + + public static void initInjector(Context context) { + enabled = SettingsUtils.getEnabled(context, SpeakerFragment.KEY_SPEAKER_TWEAKS_ENABLE); + audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + + audioManager.registerAudioPlaybackCallback(new AudioManager.AudioPlaybackCallback() { + @Override + public void onPlaybackConfigChanged(List configs) { + super.onPlaybackConfigChanged(configs); + + for (AudioPlaybackConfiguration config : configs) { + if (config == null) continue; + if (config.getAudioDeviceInfo() == null) continue; + if (config.getAudioDeviceInfo().getType() != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { + continue; + } else { + updateParameters(context); + break; + } + } + } + }, handler); + } + + public static void updateParameters(Context context) { + if (!enabled) return; + + StringBuilder builder = new StringBuilder("eq="); + builder.append(String.valueOf(SettingsUtils.getInt(context, SpeakerFragment.KEY_SPEAKER_EQ_BASE + "0", 3))); + builder.append(String.valueOf(SettingsUtils.getInt(context, SpeakerFragment.KEY_SPEAKER_EQ_BASE + "1", 3))); + builder.append(String.valueOf(SettingsUtils.getInt(context, SpeakerFragment.KEY_SPEAKER_EQ_BASE + "2", 3))); + builder.append(String.valueOf(SettingsUtils.getInt(context, SpeakerFragment.KEY_SPEAKER_EQ_BASE + "3", 3))); + builder.append(String.valueOf(SettingsUtils.getInt(context, SpeakerFragment.KEY_SPEAKER_EQ_BASE + "4", 3))); + builder.append(";gamemode="); + builder.append(sharedPreferences.getString(SpeakerFragment.KEY_SPEAKER_GAMEMODE, SpeakerFragment.GAMEMODE_DISABLED)); + String parameters = builder.toString(); + + if (DEBUG) Log.d(TAG, "Setting speaker parameters to " + parameters); + audioManager.setParameters(parameters); + } +} diff --git a/parts/src/org/lineageos/settings/utils/FileUtils.java b/parts/src/org/lineageos/settings/utils/FileUtils.java new file mode 100644 index 0000000..ffaf591 --- /dev/null +++ b/parts/src/org/lineageos/settings/utils/FileUtils.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2016 The CyanogenMod 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.utils; + +import android.util.Log; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.NullPointerException; +import java.lang.SecurityException; + +public final class FileUtils { + private static final String TAG = "FileUtils"; + + private FileUtils() { + // This class is not supposed to be instantiated + } + + /** + * Reads the first line of text from the given file. + * Reference {@link BufferedReader#readLine()} for clarification on what a line is + * + * @return the read line contents, or null on failure + */ + public static String readOneLine(String fileName) { + String line = null; + BufferedReader reader = null; + + try { + reader = new BufferedReader(new FileReader(fileName), 512); + line = reader.readLine(); + } catch (FileNotFoundException e) { + Log.w(TAG, "No such file " + fileName + " for reading", e); + } catch (IOException e) { + Log.e(TAG, "Could not read from file " + fileName, e); + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (IOException e) { + // Ignored, not much we can do anyway + } + } + + return line; + } + + /** + * Writes the given value into the given file + * + * @return true on success, false on failure + */ + public static boolean writeLine(String fileName, String value) { + BufferedWriter writer = null; + + try { + writer = new BufferedWriter(new FileWriter(fileName)); + writer.write(value); + } catch (FileNotFoundException e) { + Log.w(TAG, "No such file " + fileName + " for writing", e); + return false; + } catch (IOException e) { + Log.e(TAG, "Could not write to file " + fileName, e); + return false; + } finally { + try { + if (writer != null) { + writer.close(); + } + } catch (IOException e) { + // Ignored, not much we can do anyway + } + } + + return true; + } + + /** + * Checks whether the given file exists + * + * @return true if exists, false if not + */ + public static boolean fileExists(String fileName) { + final File file = new File(fileName); + return file.exists(); + } + + /** + * Checks whether the given file is readable + * + * @return true if readable, false if not + */ + public static boolean isFileReadable(String fileName) { + final File file = new File(fileName); + return file.exists() && file.canRead(); + } + + /** + * Checks whether the given file is writable + * + * @return true if writable, false if not + */ + public static boolean isFileWritable(String fileName) { + final File file = new File(fileName); + return file.exists() && file.canWrite(); + } + + /** + * Deletes an existing file + * + * @return true if the delete was successful, false if not + */ + public static boolean delete(String fileName) { + final File file = new File(fileName); + boolean ok = false; + try { + ok = file.delete(); + } catch (SecurityException e) { + Log.w(TAG, "SecurityException trying to delete " + fileName, e); + } + return ok; + } + + /** + * Renames an existing file + * + * @return true if the rename was successful, false if not + */ + public static boolean rename(String srcPath, String dstPath) { + final File srcFile = new File(srcPath); + final File dstFile = new File(dstPath); + boolean ok = false; + try { + ok = srcFile.renameTo(dstFile); + } catch (SecurityException e) { + Log.w(TAG, "SecurityException trying to rename " + srcPath + " to " + dstPath, e); + } catch (NullPointerException e) { + Log.e(TAG, "NullPointerException trying to rename " + srcPath + " to " + dstPath, e); + } + return ok; + } +} diff --git a/parts/src/org/lineageos/settings/utils/SettingsUtils.java b/parts/src/org/lineageos/settings/utils/SettingsUtils.java new file mode 100644 index 0000000..89bbc2d --- /dev/null +++ b/parts/src/org/lineageos/settings/utils/SettingsUtils.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 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.utils; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; + +public class SettingsUtils { + public static final String PREFERENCES = "SettingsUtilsPreferences"; + + /** + * Saves given value into given preference + * @return puts the value in place + */ + public static boolean setEnabled(Context context, String string, boolean enabled) { + return putInt(context, string, enabled ? 1 : 0); + } + + /** + * Retrieves a value from a desired string + * @return the value + */ + public static boolean getEnabled(Context context, String string) { + return getInt(context, string, 0) == 1; + } + + public static boolean putInt(Context context, String name, int value) { + SharedPreferences settings = context.getSharedPreferences(PREFERENCES, 0); + SharedPreferences.Editor editor = settings.edit(); + editor.putInt(name, value); + return editor.commit(); + } + + public static int getInt(Context context, String name, int def) { + SharedPreferences settings = context.getSharedPreferences(PREFERENCES, 0); + return settings.getInt(name, def); + } +};