dolby: Rewrite in Kotlin
Some cleanup and restructuring while we're at it. Change-Id: I2f1fc53c202d91421c7b6af68c814c25398a62e4
This commit is contained in:
parent
6a00b38d83
commit
d5620a07ee
@ -8,7 +8,7 @@
|
||||
android_app {
|
||||
name: "XiaomiDolby",
|
||||
|
||||
srcs: ["src/**/*.java"],
|
||||
srcs: ["src/**/*.kt"],
|
||||
resource_dirs: ["res"],
|
||||
certificate: "platform",
|
||||
platform_apis: true,
|
||||
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
public class BootCompletedReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "XiaomiParts-BCR";
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
Log.d(TAG, "Received intent: " + intent.getAction());
|
||||
if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Boot completed, starting dolby");
|
||||
DolbyUtils.getInstance(context).onBootCompleted();
|
||||
}
|
||||
|
||||
}
|
27
dolby/src/co/aospa/dolby/xiaomi/BootCompletedReceiver.kt
Normal file
27
dolby/src/co/aospa/dolby/xiaomi/BootCompletedReceiver.kt
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
|
||||
private const val TAG = "XiaomiDolby-Boot"
|
||||
|
||||
class BootCompletedReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Log.d(TAG, "Received intent: ${intent.action}")
|
||||
if (intent.action != Intent.ACTION_BOOT_COMPLETED) {
|
||||
return
|
||||
}
|
||||
|
||||
Log.i(TAG, "Boot completed, starting dolby")
|
||||
DolbyController.getInstance(context).onBootCompleted()
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
import com.android.settingslib.widget.R;
|
||||
|
||||
public class DolbyActivity extends CollapsingToolbarBaseActivity {
|
||||
|
||||
private static final String TAG_DOLBY = "DolbyActivity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getFragmentManager().beginTransaction().replace(R.id.content_frame,
|
||||
new DolbySettingsFragment(), TAG_DOLBY).commit();
|
||||
}
|
||||
}
|
23
dolby/src/co/aospa/dolby/xiaomi/DolbyActivity.kt
Normal file
23
dolby/src/co/aospa/dolby/xiaomi/DolbyActivity.kt
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi
|
||||
|
||||
import android.os.Bundle
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity
|
||||
import com.android.settingslib.widget.R
|
||||
|
||||
private const val TAG = "DolbyActivity"
|
||||
|
||||
class DolbyActivity : CollapsingToolbarBaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
fragmentManager.beginTransaction()
|
||||
.replace(R.id.content_frame, DolbySettingsFragment(), TAG)
|
||||
.commit()
|
||||
}
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi;
|
||||
|
||||
import android.media.audiofx.AudioEffect;
|
||||
import android.util.Log;
|
||||
|
||||
import co.aospa.dolby.xiaomi.DolbyConstants.DsParam;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
class DolbyAtmos extends AudioEffect {
|
||||
|
||||
private static final String TAG = "DolbyAtmos";
|
||||
private static final UUID EFFECT_TYPE_DAP =
|
||||
UUID.fromString("9d4921da-8225-4f29-aefa-39537a04bcaa");
|
||||
|
||||
private static final int
|
||||
EFFECT_PARAM_CPDP_VALUES = 5,
|
||||
EFFECT_PARAM_ENABLE = 0,
|
||||
EFFECT_PARAM_PROFILE = 0xA000000,
|
||||
EFFECT_PARAM_SET_PROFILE_PARAMETER = 0x1000000,
|
||||
EFFECT_PARAM_GET_PROFILE_PARAMETER = 0x1000005,
|
||||
EFFECT_PARAM_RESET_PROFILE_SETTINGS = 0xC000000;
|
||||
|
||||
DolbyAtmos(int priority, int audioSession) {
|
||||
super(EFFECT_TYPE_NULL, EFFECT_TYPE_DAP, priority, audioSession);
|
||||
}
|
||||
|
||||
private static int int32ToByteArray(int value, byte[] dst, int index) {
|
||||
dst[index++] = (byte) (value & 0xff);
|
||||
dst[index++] = (byte) ((value >>> 8) & 0xff);
|
||||
dst[index++] = (byte) ((value >>> 16) & 0xff);
|
||||
dst[index] = (byte) ((value >>> 24) & 0xff);
|
||||
return 4;
|
||||
}
|
||||
|
||||
private static int byteArrayToInt32(byte[] ba) {
|
||||
return ((ba[3] & 0xff) << 24) | ((ba[2] & 0xff) << 16)
|
||||
| ((ba[1] & 0xff) << 8) | (ba[0] & 0xff);
|
||||
}
|
||||
|
||||
private static int int32ArrayToByteArray(int[] src, byte[] dst, int index) {
|
||||
for (int x : src) {
|
||||
dst[index++] = (byte) ((x >>> 0) & 0xff);
|
||||
dst[index++] = (byte) ((x >>> 8) & 0xff);
|
||||
dst[index++] = (byte) ((x >>> 16) & 0xff);
|
||||
dst[index++] = (byte) ((x >>> 24) & 0xff);
|
||||
}
|
||||
return src.length << 2;
|
||||
}
|
||||
|
||||
private static int[] byteArrayToInt32Array(byte[] ba, int dstLength) {
|
||||
int srcLength = ba.length >> 2;
|
||||
if (dstLength > srcLength) {
|
||||
dstLength = srcLength;
|
||||
}
|
||||
int[] dst = new int[dstLength];
|
||||
for (int i = 0; i < dstLength; i++) {
|
||||
dst[i] = ((ba[i * 4 + 3] & 0xff) << 24) | ((ba[i * 4 + 2] & 0xff) << 16)
|
||||
| ((ba[i * 4 + 1] & 0xff) << 8) | (ba[i * 4] & 0xff);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
private void setIntParam(int param, int value) {
|
||||
byte[] buf = new byte[12];
|
||||
int i = int32ToByteArray(param, buf, 0);
|
||||
int32ToByteArray(value, buf, i + int32ToByteArray(1, buf, i));
|
||||
checkStatus(setParameter(EFFECT_PARAM_CPDP_VALUES, buf));
|
||||
}
|
||||
|
||||
private int getIntParam(int param) {
|
||||
byte[] buf = new byte[12];
|
||||
int32ToByteArray(param, buf, 0);
|
||||
checkStatus(getParameter(EFFECT_PARAM_CPDP_VALUES + param, buf));
|
||||
return byteArrayToInt32(buf);
|
||||
}
|
||||
|
||||
void setDsOn(boolean on) {
|
||||
setIntParam(EFFECT_PARAM_ENABLE, on ? 1 : 0);
|
||||
super.setEnabled(on);
|
||||
}
|
||||
|
||||
boolean getDsOn() {
|
||||
return getIntParam(EFFECT_PARAM_ENABLE) == 1;
|
||||
}
|
||||
|
||||
void setProfile(int index) {
|
||||
setIntParam(EFFECT_PARAM_PROFILE, index);
|
||||
}
|
||||
|
||||
int getProfile() {
|
||||
return getIntParam(EFFECT_PARAM_PROFILE);
|
||||
}
|
||||
|
||||
void resetProfileSpecificSettings() {
|
||||
int profile = getProfile();
|
||||
dlog("resetProfileSpecificSettings: profile=" + profile);
|
||||
setIntParam(EFFECT_PARAM_RESET_PROFILE_SETTINGS, profile);
|
||||
}
|
||||
|
||||
void setDapParameter(int profile, DsParam param, int values[]) {
|
||||
dlog("setDapParameter: profile=" + profile + " param=" + param);
|
||||
int length = values.length;
|
||||
byte[] buf = new byte[(length + 4) * 4];
|
||||
int i = int32ToByteArray(EFFECT_PARAM_SET_PROFILE_PARAMETER, buf, 0);
|
||||
int i2 = i + int32ToByteArray(length + 1, buf, i);
|
||||
int i3 = i2 + int32ToByteArray(profile, buf, i2);
|
||||
int32ArrayToByteArray(values, buf, i3 + int32ToByteArray(param.id, buf, i3));
|
||||
checkStatus(setParameter(EFFECT_PARAM_CPDP_VALUES, buf));
|
||||
}
|
||||
|
||||
void setDapParameter(DsParam param, int values[]) {
|
||||
setDapParameter(getProfile(), param, values);
|
||||
}
|
||||
|
||||
void setDapParameterBool(DsParam param, boolean enable) {
|
||||
setDapParameter(param, new int[]{enable ? 1 : 0});
|
||||
}
|
||||
|
||||
void setDapParameterInt(DsParam param, int value) {
|
||||
setDapParameter(param, new int[]{value});
|
||||
}
|
||||
|
||||
int[] getDapParameter(int profile, DsParam param) {
|
||||
dlog("getDapParameter: profile=" + profile + " param=" + param);
|
||||
int length = param.length;
|
||||
byte[] buf = new byte[(length + 2) * 4];
|
||||
int i = (param.id << 16) + EFFECT_PARAM_GET_PROFILE_PARAMETER;
|
||||
checkStatus(getParameter(i + (profile << 8), buf));
|
||||
return byteArrayToInt32Array(buf, length);
|
||||
}
|
||||
|
||||
int[] getDapParameter(DsParam param) {
|
||||
return getDapParameter(getProfile(), param);
|
||||
}
|
||||
|
||||
boolean getDapParameterBool(DsParam param) {
|
||||
return getDapParameter(param)[0] == 1;
|
||||
}
|
||||
|
||||
int getDapParameterInt(DsParam param) {
|
||||
return getDapParameter(param)[0];
|
||||
}
|
||||
|
||||
private static void dlog(String msg) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
}
|
||||
}
|
136
dolby/src/co/aospa/dolby/xiaomi/DolbyAudioEffect.kt
Normal file
136
dolby/src/co/aospa/dolby/xiaomi/DolbyAudioEffect.kt
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi
|
||||
|
||||
import android.media.audiofx.AudioEffect
|
||||
import co.aospa.dolby.xiaomi.DolbyConstants.Companion.dlog
|
||||
import co.aospa.dolby.xiaomi.DolbyConstants.DsParam
|
||||
import java.util.UUID
|
||||
|
||||
class DolbyAudioEffect(priority: Int, audioSession: Int) : AudioEffect(
|
||||
EFFECT_TYPE_NULL, EFFECT_TYPE_DAP, priority, audioSession
|
||||
) {
|
||||
|
||||
var dsOn: Boolean
|
||||
get() = getIntParam(EFFECT_PARAM_ENABLE) == 1
|
||||
set(value) {
|
||||
setIntParam(EFFECT_PARAM_ENABLE, if (value) 1 else 0)
|
||||
enabled = value
|
||||
}
|
||||
|
||||
var profile: Int
|
||||
get() = getIntParam(EFFECT_PARAM_PROFILE)
|
||||
set(value) {
|
||||
setIntParam(EFFECT_PARAM_PROFILE, value)
|
||||
}
|
||||
|
||||
private fun setIntParam(param: Int, value: Int) {
|
||||
dlog(TAG, "setIntParam($param, $value)")
|
||||
val buf = ByteArray(12)
|
||||
int32ToByteArray(param, buf, 0)
|
||||
int32ToByteArray(1, buf, 4)
|
||||
int32ToByteArray(value, buf, 8)
|
||||
checkStatus(setParameter(EFFECT_PARAM_CPDP_VALUES, buf))
|
||||
}
|
||||
|
||||
private fun getIntParam(param: Int): Int {
|
||||
val buf = ByteArray(12)
|
||||
int32ToByteArray(param, buf, 0)
|
||||
checkStatus(getParameter(EFFECT_PARAM_CPDP_VALUES + param, buf))
|
||||
return byteArrayToInt32(buf).also {
|
||||
dlog(TAG, "getIntParam($param): $it")
|
||||
}
|
||||
}
|
||||
|
||||
fun resetProfileSpecificSettings() {
|
||||
dlog(TAG, "resetProfileSpecificSettings: profile=$profile")
|
||||
setIntParam(EFFECT_PARAM_RESET_PROFILE_SETTINGS, profile)
|
||||
}
|
||||
|
||||
fun setDapParameter(param: DsParam, values: IntArray, profile: Int = this.profile) {
|
||||
dlog(TAG, "setDapParameter: profile=$profile param=$param")
|
||||
val length = values.size
|
||||
val buf = ByteArray((length + 4) * 4)
|
||||
int32ToByteArray(EFFECT_PARAM_SET_PROFILE_PARAMETER, buf, 0)
|
||||
int32ToByteArray(length + 1, buf, 4)
|
||||
int32ToByteArray(profile, buf, 8)
|
||||
int32ToByteArray(param.id, buf, 12)
|
||||
int32ArrayToByteArray(values, buf, 16)
|
||||
checkStatus(setParameter(EFFECT_PARAM_CPDP_VALUES, buf))
|
||||
}
|
||||
|
||||
fun setDapParameter(param: DsParam, enable: Boolean, profile: Int = this.profile) =
|
||||
setDapParameter(param, intArrayOf(if (enable) 1 else 0), profile)
|
||||
|
||||
fun setDapParameter(param: DsParam, value: Int, profile: Int = this.profile) =
|
||||
setDapParameter(param, intArrayOf(value), profile)
|
||||
|
||||
fun getDapParameter(param: DsParam, profile: Int = this.profile): IntArray {
|
||||
dlog(TAG, "getDapParameter: profile=$profile param=$param")
|
||||
val length = param.length
|
||||
val buf = ByteArray((length + 2) * 4)
|
||||
val p = (param.id shl 16) + (profile shl 8) + EFFECT_PARAM_GET_PROFILE_PARAMETER
|
||||
checkStatus(getParameter(p, buf))
|
||||
return byteArrayToInt32Array(buf, length)
|
||||
}
|
||||
|
||||
fun getDapParameterBool(param: DsParam, profile: Int = this.profile): Boolean =
|
||||
getDapParameter(param, profile)[0] == 1
|
||||
|
||||
fun getDapParameterInt(param: DsParam, profile: Int = this.profile): Int =
|
||||
getDapParameter(param, profile)[0]
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DolbyAudioEffect"
|
||||
private val EFFECT_TYPE_DAP =
|
||||
UUID.fromString("9d4921da-8225-4f29-aefa-39537a04bcaa")
|
||||
|
||||
private const val EFFECT_PARAM_ENABLE = 0
|
||||
private const val EFFECT_PARAM_CPDP_VALUES = 5
|
||||
private const val EFFECT_PARAM_PROFILE = 0xA000000
|
||||
private const val EFFECT_PARAM_SET_PROFILE_PARAMETER = 0x1000000
|
||||
private const val EFFECT_PARAM_GET_PROFILE_PARAMETER = 0x1000005
|
||||
private const val EFFECT_PARAM_RESET_PROFILE_SETTINGS = 0xC000000
|
||||
|
||||
private fun int32ToByteArray(value: Int, dst: ByteArray, index: Int) {
|
||||
var idx = index
|
||||
dst[idx++] = (value and 0xff).toByte()
|
||||
dst[idx++] = ((value ushr 8) and 0xff).toByte()
|
||||
dst[idx++] = ((value ushr 16) and 0xff).toByte()
|
||||
dst[idx] = ((value ushr 24) and 0xff).toByte()
|
||||
}
|
||||
|
||||
private fun byteArrayToInt32(ba: ByteArray): Int {
|
||||
return ((ba[3].toInt() and 0xff) shl 24) or
|
||||
((ba[2].toInt() and 0xff) shl 16) or
|
||||
((ba[1].toInt() and 0xff) shl 8) or
|
||||
(ba[0].toInt() and 0xff)
|
||||
}
|
||||
|
||||
private fun int32ArrayToByteArray(src: IntArray, dst: ByteArray, index: Int) {
|
||||
var idx = index
|
||||
for (x in src) {
|
||||
dst[idx++] = (x and 0xff).toByte()
|
||||
dst[idx++] = ((x ushr 8) and 0xff).toByte()
|
||||
dst[idx++] = ((x ushr 16) and 0xff).toByte()
|
||||
dst[idx++] = ((x ushr 24) and 0xff).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
private fun byteArrayToInt32Array(ba: ByteArray, dstLength: Int): IntArray {
|
||||
val srcLength = ba.size shr 2
|
||||
val dst = IntArray(dstLength.coerceAtMost(srcLength))
|
||||
for (i in dst.indices) {
|
||||
dst[i] = ((ba[i * 4 + 3].toInt() and 0xff) shl 24) or
|
||||
((ba[i * 4 + 2].toInt() and 0xff) shl 16) or
|
||||
((ba[i * 4 + 1].toInt() and 0xff) shl 8) or
|
||||
(ba[i * 4].toInt() and 0xff)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi;
|
||||
|
||||
class DolbyConstants {
|
||||
|
||||
enum DsParam {
|
||||
HEADPHONE_VIRTUALIZER(101),
|
||||
SPEAKER_VIRTUALIZER(102),
|
||||
VOLUME_LEVELER_ENABLE(103),
|
||||
DIALOGUE_ENHANCER_ENABLE(105),
|
||||
DIALOGUE_ENHANCER_AMOUNT(108),
|
||||
GEQ_BAND_GAINS(110, 20),
|
||||
BASS_ENHANCER_ENABLE(111),
|
||||
STEREO_WIDENING_AMOUNT(113),
|
||||
VOLUME_LEVELER_AMOUNT(116);
|
||||
|
||||
public int id, length;
|
||||
|
||||
DsParam(int id, int length) {
|
||||
this.id = id;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
DsParam(int id) {
|
||||
this(id, 1);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", name(), id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
47
dolby/src/co/aospa/dolby/xiaomi/DolbyConstants.kt
Normal file
47
dolby/src/co/aospa/dolby/xiaomi/DolbyConstants.kt
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi
|
||||
|
||||
import android.util.Log
|
||||
|
||||
class DolbyConstants {
|
||||
|
||||
enum class DsParam(val id: Int, val length: Int = 1) {
|
||||
HEADPHONE_VIRTUALIZER(101),
|
||||
SPEAKER_VIRTUALIZER(102),
|
||||
VOLUME_LEVELER_ENABLE(103),
|
||||
DIALOGUE_ENHANCER_ENABLE(105),
|
||||
DIALOGUE_ENHANCER_AMOUNT(108),
|
||||
GEQ_BAND_GAINS(110, 20),
|
||||
BASS_ENHANCER_ENABLE(111),
|
||||
STEREO_WIDENING_AMOUNT(113),
|
||||
VOLUME_LEVELER_AMOUNT(116);
|
||||
|
||||
override fun toString(): String {
|
||||
return "${name}(${id})"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "XiaomiDolby"
|
||||
const val PREF_ENABLE = "dolby_enable"
|
||||
const val PREF_PROFILE = "dolby_profile"
|
||||
const val PREF_PRESET = "dolby_preset"
|
||||
const val PREF_VIRTUALIZER = "dolby_virtualizer"
|
||||
const val PREF_STEREO = "dolby_stereo"
|
||||
const val PREF_DIALOGUE = "dolby_dialogue"
|
||||
const val PREF_BASS = "dolby_bass"
|
||||
const val PREF_VOLUME = "dolby_volume"
|
||||
const val PREF_RESET = "dolby_reset"
|
||||
|
||||
fun dlog(tag: String, msg: String) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(tag, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
247
dolby/src/co/aospa/dolby/xiaomi/DolbyController.kt
Normal file
247
dolby/src/co/aospa/dolby/xiaomi/DolbyController.kt
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioDeviceCallback
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.media.AudioManager
|
||||
import android.media.AudioManager.AudioPlaybackCallback
|
||||
import android.media.AudioPlaybackConfiguration
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import co.aospa.dolby.xiaomi.DolbyConstants.Companion.dlog
|
||||
import co.aospa.dolby.xiaomi.DolbyConstants.DsParam
|
||||
import co.aospa.dolby.xiaomi.R
|
||||
|
||||
internal class DolbyController private constructor(
|
||||
private val context: Context
|
||||
) {
|
||||
private var dolbyEffect = DolbyAudioEffect(EFFECT_PRIORITY, audioSession = 0)
|
||||
private val audioManager = context.getSystemService(AudioManager::class.java)
|
||||
private val handler = Handler(context.mainLooper)
|
||||
|
||||
// Restore current profile on every media session
|
||||
private val playbackCallback = object : AudioPlaybackCallback() {
|
||||
override fun onPlaybackConfigChanged(configs: List<AudioPlaybackConfiguration>) {
|
||||
val isPlaying = configs.any {
|
||||
it.playerState == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
|
||||
}
|
||||
dlog(TAG, "onPlaybackConfigChanged: isPlaying=$isPlaying")
|
||||
if (isPlaying)
|
||||
setCurrentProfile()
|
||||
}
|
||||
}
|
||||
|
||||
// Restore current profile on audio device change
|
||||
private val audioDeviceCallback = object : AudioDeviceCallback() {
|
||||
override fun onAudioDevicesAdded(addedDevices: Array<AudioDeviceInfo>) {
|
||||
dlog(TAG, "onAudioDevicesAdded")
|
||||
setCurrentProfile()
|
||||
}
|
||||
|
||||
override fun onAudioDevicesRemoved(removedDevices: Array<AudioDeviceInfo>) {
|
||||
dlog(TAG, "onAudioDevicesRemoved")
|
||||
setCurrentProfile()
|
||||
}
|
||||
}
|
||||
|
||||
private var registerCallbacks = false
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
field = value
|
||||
dlog(TAG, "setRegisterCallbacks($value)")
|
||||
if (value) {
|
||||
audioManager.registerAudioPlaybackCallback(playbackCallback, handler)
|
||||
audioManager.registerAudioDeviceCallback(audioDeviceCallback, handler)
|
||||
} else {
|
||||
audioManager.unregisterAudioPlaybackCallback(playbackCallback)
|
||||
audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)
|
||||
}
|
||||
}
|
||||
|
||||
var dsOn: Boolean
|
||||
get() =
|
||||
dolbyEffect.dsOn.also {
|
||||
dlog(TAG, "getDsOn: $it")
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setDsOn: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.dsOn = value
|
||||
registerCallbacks = value
|
||||
if (value)
|
||||
setCurrentProfile()
|
||||
}
|
||||
|
||||
var profile: Int
|
||||
get() =
|
||||
dolbyEffect.profile.also {
|
||||
dlog(TAG, "getProfile: $it")
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setProfile: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.profile = value
|
||||
}
|
||||
|
||||
var preset: String
|
||||
get() {
|
||||
val gains = dolbyEffect.getDapParameter(DsParam.GEQ_BAND_GAINS)
|
||||
return gains.joinToString(separator = ",").also {
|
||||
dlog(TAG, "getPreset: $it")
|
||||
}
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setPreset: $value")
|
||||
checkEffect()
|
||||
val gains = value.split(",")
|
||||
.map { it.toInt() }
|
||||
.toIntArray()
|
||||
dolbyEffect.setDapParameter(DsParam.GEQ_BAND_GAINS, gains)
|
||||
}
|
||||
|
||||
var headphoneVirtEnabled: Boolean
|
||||
get() =
|
||||
dolbyEffect.getDapParameterBool(DsParam.HEADPHONE_VIRTUALIZER).also {
|
||||
dlog(TAG, "getHeadphoneVirtEnabled: $it")
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setHeadphoneVirtEnabled: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.HEADPHONE_VIRTUALIZER, value)
|
||||
}
|
||||
|
||||
var speakerVirtEnabled: Boolean
|
||||
get() =
|
||||
dolbyEffect.getDapParameterBool(DsParam.SPEAKER_VIRTUALIZER).also {
|
||||
dlog(TAG, "getSpeakerVirtEnabled: $it")
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setSpeakerVirtEnabled: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.SPEAKER_VIRTUALIZER, value)
|
||||
}
|
||||
|
||||
var bassEnhancerEnabled: Boolean
|
||||
get() =
|
||||
dolbyEffect.getDapParameterBool(DsParam.BASS_ENHANCER_ENABLE).also {
|
||||
dlog(TAG, "getBassEnhancerEnabled: $it")
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setBassEnhancerEnabled: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.BASS_ENHANCER_ENABLE, value)
|
||||
}
|
||||
|
||||
var volumeLevelerEnabled: Boolean
|
||||
get() {
|
||||
val enabled = dolbyEffect.getDapParameterBool(DsParam.VOLUME_LEVELER_ENABLE)
|
||||
val amount = dolbyEffect.getDapParameterInt(DsParam.VOLUME_LEVELER_AMOUNT)
|
||||
dlog(TAG, "getVolumeLevelerEnabled: enabled=$enabled amount=$amount")
|
||||
return enabled && amount > 0
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setVolumeLevelerEnabled: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.VOLUME_LEVELER_ENABLE, value)
|
||||
dolbyEffect.setDapParameter(
|
||||
DsParam.VOLUME_LEVELER_AMOUNT,
|
||||
if (value) VOLUME_LEVELER_AMOUNT else 0
|
||||
)
|
||||
}
|
||||
|
||||
var stereoWideningAmount: Int
|
||||
get() =
|
||||
dolbyEffect.getDapParameterInt(DsParam.STEREO_WIDENING_AMOUNT).also {
|
||||
dlog(TAG, "getStereoWideningAmount: $it")
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setStereoWideningAmount: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.STEREO_WIDENING_AMOUNT, value)
|
||||
}
|
||||
|
||||
var dialogueEnhancerAmount: Int
|
||||
get() {
|
||||
val enabled = dolbyEffect.getDapParameterBool(DsParam.DIALOGUE_ENHANCER_ENABLE)
|
||||
val amount = if (enabled) {
|
||||
dolbyEffect.getDapParameterInt(DsParam.DIALOGUE_ENHANCER_AMOUNT)
|
||||
} else 0
|
||||
dlog(TAG, "getDialogueEnhancerAmount: enabled=$enabled amount=$amount")
|
||||
return amount
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setDialogueEnhancerAmount: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.DIALOGUE_ENHANCER_ENABLE, (value > 0))
|
||||
dolbyEffect.setDapParameter(DsParam.DIALOGUE_ENHANCER_AMOUNT, value)
|
||||
}
|
||||
|
||||
init {
|
||||
dlog(TAG, "initialized")
|
||||
}
|
||||
|
||||
fun onBootCompleted() {
|
||||
dlog(TAG, "onBootCompleted")
|
||||
|
||||
// Restore current profile now and on certain audio changes.
|
||||
val on = dsOn
|
||||
dolbyEffect.enabled = on
|
||||
registerCallbacks = on
|
||||
if (on)
|
||||
setCurrentProfile()
|
||||
}
|
||||
|
||||
private fun checkEffect() {
|
||||
if (!dolbyEffect.hasControl()) {
|
||||
Log.w(TAG, "lost control, recreating effect")
|
||||
dolbyEffect.release()
|
||||
dolbyEffect = DolbyAudioEffect(EFFECT_PRIORITY, audioSession = 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCurrentProfile() {
|
||||
if (!dsOn) {
|
||||
dlog(TAG, "setCurrentProfile: skip, dolby is off")
|
||||
return
|
||||
}
|
||||
dlog(TAG, "setCurrentProfile")
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
profile = prefs.getString(DolbyConstants.PREF_PROFILE, "0" /*dynamic*/).toInt()
|
||||
}
|
||||
|
||||
fun getProfileName(): String? {
|
||||
val profile = dolbyEffect.profile.toString()
|
||||
val profiles = context.resources.getStringArray(R.array.dolby_profile_values)
|
||||
val profileIndex = profiles.indexOf(profile)
|
||||
dlog(TAG, "getProfileName: profile=$profile index=$profileIndex")
|
||||
return if (profileIndex == -1) null else context.resources.getStringArray(
|
||||
R.array.dolby_profile_entries
|
||||
)[profileIndex]
|
||||
}
|
||||
|
||||
fun resetProfileSpecificSettings() {
|
||||
checkEffect()
|
||||
dolbyEffect.resetProfileSpecificSettings()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DolbyController"
|
||||
private const val EFFECT_PRIORITY = 100
|
||||
private const val VOLUME_LEVELER_AMOUNT = 2
|
||||
|
||||
@Volatile
|
||||
private var instance: DolbyController? = null
|
||||
|
||||
fun getInstance(context: Context) =
|
||||
instance ?: synchronized(this) {
|
||||
instance ?: DolbyController(context).also { instance = it }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,260 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi;
|
||||
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioDeviceAttributes;
|
||||
import android.media.AudioDeviceCallback;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.widget.Switch;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.Preference.OnPreferenceChangeListener;
|
||||
import androidx.preference.PreferenceFragment;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settingslib.widget.MainSwitchPreference;
|
||||
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
||||
|
||||
import co.aospa.dolby.xiaomi.R;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class DolbySettingsFragment extends PreferenceFragment implements
|
||||
OnPreferenceChangeListener, OnMainSwitchChangeListener {
|
||||
|
||||
private static final String TAG = "DolbySettingsFragment";
|
||||
|
||||
private static final AudioAttributes ATTRIBUTES_MEDIA = new AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||
.build();
|
||||
|
||||
public static final String PREF_ENABLE = "dolby_enable";
|
||||
public static final String PREF_PROFILE = "dolby_profile";
|
||||
public static final String PREF_PRESET = "dolby_preset";
|
||||
public static final String PREF_VIRTUALIZER = "dolby_virtualizer";
|
||||
public static final String PREF_STEREO = "dolby_stereo";
|
||||
public static final String PREF_DIALOGUE = "dolby_dialogue";
|
||||
public static final String PREF_BASS = "dolby_bass";
|
||||
public static final String PREF_VOLUME = "dolby_volume";
|
||||
public static final String PREF_RESET = "dolby_reset";
|
||||
|
||||
private MainSwitchPreference mSwitchBar;
|
||||
private ListPreference mProfilePref, mPresetPref, mStereoPref, mDialoguePref;
|
||||
private SwitchPreference mBassPref, mVirtualizerPref, mVolumePref;
|
||||
private Preference mResetPref;
|
||||
private CharSequence[] mPresets, mDeValues, mSwValues;
|
||||
|
||||
private DolbyUtils mDolbyUtils;
|
||||
private AudioManager mAudioManager;
|
||||
private boolean mDsOn, mIsOnSpeaker;
|
||||
private int mCurrentProfile = -1;
|
||||
private final Handler mHandler = new Handler();
|
||||
|
||||
private final AudioDeviceCallback mAudioDeviceCallback = new AudioDeviceCallback() {
|
||||
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
|
||||
updateSpeakerState(false);
|
||||
}
|
||||
|
||||
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
|
||||
updateSpeakerState(false);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.dolby_settings);
|
||||
|
||||
mAudioManager = getActivity().getSystemService(AudioManager.class);
|
||||
mDolbyUtils = DolbyUtils.getInstance(getActivity());
|
||||
mDsOn = mDolbyUtils.getDsOn();
|
||||
|
||||
mSwitchBar = (MainSwitchPreference) findPreference(PREF_ENABLE);
|
||||
mSwitchBar.addOnSwitchChangeListener(this);
|
||||
mSwitchBar.setChecked(mDsOn);
|
||||
|
||||
mProfilePref = (ListPreference) findPreference(PREF_PROFILE);
|
||||
mProfilePref.setOnPreferenceChangeListener(this);
|
||||
mProfilePref.setEnabled(mDsOn);
|
||||
|
||||
final CharSequence[] profiles = mProfilePref.getEntryValues();
|
||||
final int profile = mDolbyUtils.getProfile();
|
||||
if (Arrays.asList(profiles).contains(Integer.toString(profile))) {
|
||||
mCurrentProfile = profile;
|
||||
mProfilePref.setSummary("%s");
|
||||
mProfilePref.setValue(Integer.toString(profile));
|
||||
} else {
|
||||
mCurrentProfile = -1;
|
||||
mProfilePref.setSummary(getActivity().getString(R.string.dolby_unknown));
|
||||
}
|
||||
|
||||
mPresetPref = (ListPreference) findPreference(PREF_PRESET);
|
||||
mPresetPref.setOnPreferenceChangeListener(this);
|
||||
mPresets = mPresetPref.getEntryValues();
|
||||
|
||||
mVirtualizerPref = (SwitchPreference) findPreference(PREF_VIRTUALIZER);
|
||||
mVirtualizerPref.setOnPreferenceChangeListener(this);
|
||||
|
||||
mStereoPref = (ListPreference) findPreference(PREF_STEREO);
|
||||
mStereoPref.setOnPreferenceChangeListener(this);
|
||||
mSwValues = mStereoPref.getEntryValues();
|
||||
|
||||
mDialoguePref = (ListPreference) findPreference(PREF_DIALOGUE);
|
||||
mDialoguePref.setOnPreferenceChangeListener(this);
|
||||
mDeValues = mDialoguePref.getEntryValues();
|
||||
|
||||
mBassPref = (SwitchPreference) findPreference(PREF_BASS);
|
||||
mBassPref.setOnPreferenceChangeListener(this);
|
||||
|
||||
mVolumePref = (SwitchPreference) findPreference(PREF_VOLUME);
|
||||
mVolumePref.setOnPreferenceChangeListener(this);
|
||||
|
||||
mResetPref = (Preference) findPreference(PREF_RESET);
|
||||
mResetPref.setOnPreferenceClickListener(p -> {
|
||||
mDolbyUtils.resetProfileSpecificSettings();
|
||||
updateProfileSpecificPrefs();
|
||||
Toast.makeText(getActivity(),
|
||||
getActivity().getString(R.string.dolby_reset_profile_toast,
|
||||
mProfilePref.getSummary()), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
mAudioManager.registerAudioDeviceCallback(mAudioDeviceCallback, mHandler);
|
||||
updateSpeakerState(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
mAudioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
switch (preference.getKey()) {
|
||||
case PREF_PROFILE:
|
||||
mCurrentProfile = Integer.parseInt((newValue.toString()));
|
||||
mDolbyUtils.setProfile(mCurrentProfile);
|
||||
updateProfileSpecificPrefs();
|
||||
return true;
|
||||
case PREF_PRESET:
|
||||
mDolbyUtils.setPreset(newValue.toString());
|
||||
return true;
|
||||
case PREF_VIRTUALIZER:
|
||||
if (mIsOnSpeaker)
|
||||
mDolbyUtils.setSpeakerVirtualizerEnabled((Boolean) newValue);
|
||||
else
|
||||
mDolbyUtils.setHeadphoneVirtualizerEnabled((Boolean) newValue);
|
||||
return true;
|
||||
case PREF_STEREO:
|
||||
mDolbyUtils.setStereoWideningAmount(Integer.parseInt((newValue.toString())));
|
||||
return true;
|
||||
case PREF_DIALOGUE:
|
||||
mDolbyUtils.setDialogueEnhancerAmount(Integer.parseInt((newValue.toString())));
|
||||
return true;
|
||||
case PREF_BASS:
|
||||
mDolbyUtils.setBassEnhancerEnabled((Boolean) newValue);
|
||||
return true;
|
||||
case PREF_VOLUME:
|
||||
mDolbyUtils.setVolumeLevelerEnabled((Boolean) newValue);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
||||
mDsOn = isChecked;
|
||||
mDolbyUtils.setDsOn(isChecked);
|
||||
mProfilePref.setEnabled(isChecked);
|
||||
mResetPref.setEnabled(isChecked);
|
||||
updateProfileSpecificPrefs();
|
||||
}
|
||||
|
||||
private void updateSpeakerState(boolean force) {
|
||||
final AudioDeviceAttributes device =
|
||||
mAudioManager.getDevicesForAttributes(ATTRIBUTES_MEDIA).get(0);
|
||||
final boolean isOnSpeaker = (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
|
||||
if (mIsOnSpeaker != isOnSpeaker || force) {
|
||||
dlog("updateSpeakerState: " + mIsOnSpeaker);
|
||||
mIsOnSpeaker = isOnSpeaker;
|
||||
updateProfileSpecificPrefs();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProfileSpecificPrefs() {
|
||||
final String unknownRes = getActivity().getString(R.string.dolby_unknown);
|
||||
final String headphoneRes = getActivity().getString(R.string.dolby_connect_headphones);
|
||||
|
||||
dlog("updateProfileSpecificPrefs: mDsOn=" + mDsOn
|
||||
+ " mCurrentProfile=" + mCurrentProfile + " mIsOnSpeaker=" + mIsOnSpeaker);
|
||||
|
||||
final boolean enable = mDsOn && (mCurrentProfile != -1);
|
||||
|
||||
mPresetPref.setEnabled(enable);
|
||||
mVirtualizerPref.setEnabled(enable);
|
||||
mDialoguePref.setEnabled(enable);
|
||||
mVolumePref.setEnabled(enable);
|
||||
mResetPref.setEnabled(enable);
|
||||
|
||||
mStereoPref.setEnabled(enable && !mIsOnSpeaker);
|
||||
mBassPref.setEnabled(enable && !mIsOnSpeaker);
|
||||
|
||||
if (!enable) return;
|
||||
|
||||
final String preset = mDolbyUtils.getPreset();
|
||||
if (Arrays.asList(mPresets).contains(preset)) {
|
||||
mPresetPref.setSummary("%s");
|
||||
mPresetPref.setValue(preset);
|
||||
} else {
|
||||
mPresetPref.setSummary(unknownRes);
|
||||
}
|
||||
|
||||
final String deValue = Integer.toString(mDolbyUtils.getDialogueEnhancerAmount());
|
||||
if (Arrays.asList(mDeValues).contains(deValue)) {
|
||||
mDialoguePref.setSummary("%s");
|
||||
mDialoguePref.setValue(deValue);
|
||||
} else {
|
||||
mDialoguePref.setSummary(unknownRes);
|
||||
}
|
||||
|
||||
mVirtualizerPref.setChecked(mIsOnSpeaker ? mDolbyUtils.getSpeakerVirtualizerEnabled()
|
||||
: mDolbyUtils.getHeadphoneVirtualizerEnabled());
|
||||
mVolumePref.setChecked(mDolbyUtils.getVolumeLevelerEnabled());
|
||||
|
||||
if (mIsOnSpeaker) {
|
||||
mStereoPref.setSummary(headphoneRes);
|
||||
mBassPref.setSummary(headphoneRes);
|
||||
return;
|
||||
}
|
||||
|
||||
final String swValue = Integer.toString(mDolbyUtils.getStereoWideningAmount());
|
||||
if (Arrays.asList(mSwValues).contains(swValue)) {
|
||||
mStereoPref.setSummary("%s");
|
||||
mStereoPref.setValue(swValue);
|
||||
} else {
|
||||
mStereoPref.setSummary(unknownRes);
|
||||
}
|
||||
|
||||
mBassPref.setChecked(mDolbyUtils.getBassEnhancerEnabled());
|
||||
mBassPref.setSummary(null);
|
||||
}
|
||||
|
||||
private static void dlog(String msg) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
}
|
||||
}
|
263
dolby/src/co/aospa/dolby/xiaomi/DolbySettingsFragment.kt
Normal file
263
dolby/src/co/aospa/dolby/xiaomi/DolbySettingsFragment.kt
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi
|
||||
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioDeviceCallback
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.media.AudioManager
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.widget.Switch
|
||||
import android.widget.Toast
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.Preference.OnPreferenceChangeListener
|
||||
import androidx.preference.PreferenceFragment
|
||||
import androidx.preference.SwitchPreference
|
||||
import co.aospa.dolby.xiaomi.DolbyConstants.Companion.dlog
|
||||
import co.aospa.dolby.xiaomi.R
|
||||
import com.android.settingslib.widget.MainSwitchPreference
|
||||
import com.android.settingslib.widget.OnMainSwitchChangeListener
|
||||
|
||||
class DolbySettingsFragment : PreferenceFragment(),
|
||||
OnPreferenceChangeListener, OnMainSwitchChangeListener {
|
||||
|
||||
private val switchBar by lazy {
|
||||
findPreference<MainSwitchPreference>(DolbyConstants.PREF_ENABLE)!!
|
||||
}
|
||||
private val profilePref by lazy {
|
||||
findPreference<ListPreference>(DolbyConstants.PREF_PROFILE)!!
|
||||
}
|
||||
private val presetPref by lazy {
|
||||
findPreference<ListPreference>(DolbyConstants.PREF_PRESET)!!
|
||||
}
|
||||
private val stereoPref by lazy {
|
||||
findPreference<ListPreference>(DolbyConstants.PREF_STEREO)!!
|
||||
}
|
||||
private val dialoguePref by lazy {
|
||||
findPreference<ListPreference>(DolbyConstants.PREF_DIALOGUE)!!
|
||||
}
|
||||
private val bassPref by lazy {
|
||||
findPreference<SwitchPreference>(DolbyConstants.PREF_BASS)!!
|
||||
}
|
||||
private val virtPref by lazy {
|
||||
findPreference<SwitchPreference>(DolbyConstants.PREF_VIRTUALIZER)!!
|
||||
}
|
||||
private val volumePref by lazy {
|
||||
findPreference<SwitchPreference>(DolbyConstants.PREF_VOLUME)!!
|
||||
}
|
||||
private val resetPref by lazy {
|
||||
findPreference<Preference>(DolbyConstants.PREF_RESET)!!
|
||||
}
|
||||
|
||||
private val dolbyController by lazy { DolbyController.getInstance(context) }
|
||||
private val audioManager by lazy { context.getSystemService(AudioManager::class.java) }
|
||||
private val handler = Handler()
|
||||
|
||||
private var isOnSpeaker = true
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
field = value
|
||||
dlog(TAG, "setIsOnSpeaker($value)")
|
||||
updateProfileSpecificPrefs()
|
||||
}
|
||||
|
||||
private val audioDeviceCallback = object : AudioDeviceCallback() {
|
||||
override fun onAudioDevicesAdded(addedDevices: Array<AudioDeviceInfo>) {
|
||||
dlog(TAG, "onAudioDevicesAdded")
|
||||
updateSpeakerState()
|
||||
}
|
||||
|
||||
override fun onAudioDevicesRemoved(removedDevices: Array<AudioDeviceInfo>) {
|
||||
dlog(TAG, "onAudioDevicesRemoved")
|
||||
updateSpeakerState()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
dlog(TAG, "onCreatePreferences")
|
||||
addPreferencesFromResource(R.xml.dolby_settings)
|
||||
|
||||
val dsOn = dolbyController.dsOn
|
||||
switchBar.addOnSwitchChangeListener(this)
|
||||
switchBar.setChecked(dsOn)
|
||||
|
||||
profilePref.onPreferenceChangeListener = this
|
||||
profilePref.setEnabled(dsOn)
|
||||
|
||||
val profile = dolbyController.profile
|
||||
profilePref.apply {
|
||||
if (entryValues.contains(profile.toString())) {
|
||||
summary = "%s"
|
||||
value = profile.toString()
|
||||
} else {
|
||||
summary = context.getString(R.string.dolby_unknown)
|
||||
}
|
||||
}
|
||||
|
||||
presetPref.onPreferenceChangeListener = this
|
||||
virtPref.onPreferenceChangeListener = this
|
||||
stereoPref.onPreferenceChangeListener = this
|
||||
dialoguePref.onPreferenceChangeListener = this
|
||||
bassPref.onPreferenceChangeListener = this
|
||||
volumePref.onPreferenceChangeListener = this
|
||||
|
||||
resetPref.setOnPreferenceClickListener {
|
||||
dolbyController.resetProfileSpecificSettings()
|
||||
updateProfileSpecificPrefs()
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.dolby_reset_profile_toast, profilePref.summary),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
true
|
||||
}
|
||||
|
||||
audioManager.registerAudioDeviceCallback(audioDeviceCallback, handler)
|
||||
updateSpeakerState()
|
||||
updateProfileSpecificPrefs()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
dlog(TAG, "onDestroyView")
|
||||
audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
|
||||
dlog(TAG, "onPreferenceChange: key=${preference.key} value=$newValue")
|
||||
when (preference.key) {
|
||||
DolbyConstants.PREF_PROFILE -> {
|
||||
dolbyController.profile = newValue.toString().toInt()
|
||||
updateProfileSpecificPrefs()
|
||||
}
|
||||
|
||||
DolbyConstants.PREF_PRESET -> {
|
||||
dolbyController.preset = newValue.toString()
|
||||
}
|
||||
|
||||
DolbyConstants.PREF_VIRTUALIZER -> {
|
||||
if (isOnSpeaker)
|
||||
dolbyController.speakerVirtEnabled = newValue as Boolean
|
||||
else
|
||||
dolbyController.headphoneVirtEnabled = newValue as Boolean
|
||||
}
|
||||
|
||||
DolbyConstants.PREF_STEREO -> {
|
||||
dolbyController.stereoWideningAmount = newValue.toString().toInt()
|
||||
}
|
||||
|
||||
DolbyConstants.PREF_DIALOGUE -> {
|
||||
dolbyController.dialogueEnhancerAmount = newValue.toString().toInt()
|
||||
}
|
||||
|
||||
DolbyConstants.PREF_BASS -> {
|
||||
dolbyController.bassEnhancerEnabled = newValue as Boolean
|
||||
}
|
||||
|
||||
DolbyConstants.PREF_VOLUME -> {
|
||||
dolbyController.volumeLevelerEnabled = newValue as Boolean
|
||||
}
|
||||
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwitchChanged(switchView: Switch, isChecked: Boolean) {
|
||||
dlog(TAG, "onSwitchChanged($isChecked)")
|
||||
dolbyController.dsOn = isChecked
|
||||
profilePref.setEnabled(isChecked)
|
||||
updateProfileSpecificPrefs()
|
||||
}
|
||||
|
||||
private fun updateSpeakerState() {
|
||||
val device = audioManager.getDevicesForAttributes(ATTRIBUTES_MEDIA)[0]
|
||||
isOnSpeaker = (device.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER)
|
||||
}
|
||||
|
||||
private fun updateProfileSpecificPrefs() {
|
||||
val unknownRes = context.getString(R.string.dolby_unknown)
|
||||
val headphoneRes = context.getString(R.string.dolby_connect_headphones)
|
||||
val dsOn = dolbyController.dsOn
|
||||
val currentProfile = dolbyController.profile
|
||||
|
||||
dlog(
|
||||
TAG, "updateProfileSpecificPrefs: dsOn=$dsOn currentProfile=$currentProfile"
|
||||
+ " isOnSpeaker=$isOnSpeaker"
|
||||
)
|
||||
|
||||
val enable = dsOn && (currentProfile != -1)
|
||||
presetPref.setEnabled(enable)
|
||||
virtPref.setEnabled(enable)
|
||||
dialoguePref.setEnabled(enable)
|
||||
volumePref.setEnabled(enable)
|
||||
resetPref.setEnabled(enable)
|
||||
stereoPref.setEnabled(enable && !isOnSpeaker)
|
||||
bassPref.setEnabled(enable && !isOnSpeaker)
|
||||
|
||||
if (!enable) return
|
||||
|
||||
val preset = dolbyController.preset
|
||||
presetPref.apply {
|
||||
if (entryValues.contains(preset)) {
|
||||
summary = "%s"
|
||||
value = preset
|
||||
} else {
|
||||
summary = unknownRes
|
||||
}
|
||||
}
|
||||
|
||||
val deValue = dolbyController.dialogueEnhancerAmount.toString()
|
||||
dialoguePref.apply {
|
||||
if (entryValues.contains(deValue)) {
|
||||
summary = "%s"
|
||||
value = deValue
|
||||
} else {
|
||||
summary = unknownRes
|
||||
}
|
||||
}
|
||||
|
||||
virtPref.setChecked(if (isOnSpeaker) {
|
||||
dolbyController.speakerVirtEnabled
|
||||
} else {
|
||||
dolbyController.headphoneVirtEnabled
|
||||
})
|
||||
|
||||
volumePref.setChecked(dolbyController.volumeLevelerEnabled)
|
||||
|
||||
// below prefs are not enabled on loudspeaker
|
||||
if (isOnSpeaker) {
|
||||
stereoPref.summary = headphoneRes
|
||||
bassPref.summary = headphoneRes
|
||||
return
|
||||
}
|
||||
|
||||
val swValue = dolbyController.stereoWideningAmount.toString()
|
||||
stereoPref.apply {
|
||||
if (entryValues.contains(swValue)) {
|
||||
summary = "%s"
|
||||
value = swValue
|
||||
} else {
|
||||
summary = unknownRes
|
||||
}
|
||||
}
|
||||
|
||||
bassPref.apply {
|
||||
setChecked(dolbyController.bassEnhancerEnabled)
|
||||
summary = null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DolbySettingsFragment"
|
||||
private val ATTRIBUTES_MEDIA = AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||
.build()
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi;
|
||||
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
|
||||
public class DolbyTileService extends TileService {
|
||||
|
||||
private static final String TAG = "DolbyTileService";
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
Tile tile = getQsTile();
|
||||
DolbyUtils dolbyUtils = DolbyUtils.getInstance(getApplicationContext());
|
||||
if (dolbyUtils.getDsOn()) {
|
||||
tile.setState(Tile.STATE_ACTIVE);
|
||||
} else {
|
||||
tile.setState(Tile.STATE_INACTIVE);
|
||||
}
|
||||
tile.setSubtitle(dolbyUtils.getProfileName());
|
||||
tile.updateTile();
|
||||
super.onStartListening();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
Tile tile = getQsTile();
|
||||
DolbyUtils dolbyUtils = DolbyUtils.getInstance(getApplicationContext());
|
||||
if (dolbyUtils.getDsOn()) {
|
||||
dolbyUtils.setDsOn(false);
|
||||
tile.setState(Tile.STATE_INACTIVE);
|
||||
} else {
|
||||
dolbyUtils.setDsOn(true);
|
||||
tile.setState(Tile.STATE_ACTIVE);
|
||||
}
|
||||
tile.updateTile();
|
||||
super.onClick();
|
||||
}
|
||||
}
|
36
dolby/src/co/aospa/dolby/xiaomi/DolbyTileService.kt
Normal file
36
dolby/src/co/aospa/dolby/xiaomi/DolbyTileService.kt
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi
|
||||
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
|
||||
private const val TAG = "DolbyTileService"
|
||||
|
||||
class DolbyTileService : TileService() {
|
||||
|
||||
private val dolbyController by lazy { DolbyController.getInstance(applicationContext) }
|
||||
|
||||
override fun onStartListening() {
|
||||
qsTile.apply {
|
||||
state = if (dolbyController.dsOn) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
|
||||
subtitle = dolbyController.getProfileName() ?: getString(R.string.dolby_unknown)
|
||||
updateTile()
|
||||
}
|
||||
super.onStartListening()
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
val isDsOn = dolbyController.dsOn
|
||||
dolbyController.dsOn = !isDsOn
|
||||
qsTile.apply {
|
||||
state = if (isDsOn) Tile.STATE_INACTIVE else Tile.STATE_ACTIVE
|
||||
updateTile()
|
||||
}
|
||||
super.onClick()
|
||||
}
|
||||
}
|
@ -1,262 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.media.AudioDeviceCallback;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioManager.AudioPlaybackCallback;
|
||||
import android.media.AudioPlaybackConfiguration;
|
||||
import android.media.session.MediaSessionManager;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import co.aospa.dolby.xiaomi.DolbyConstants.DsParam;
|
||||
import co.aospa.dolby.xiaomi.R;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class DolbyUtils {
|
||||
|
||||
private static final String TAG = "DolbyUtils";
|
||||
private static final int EFFECT_PRIORITY = 100;
|
||||
private static final int VOLUME_LEVELER_AMOUNT = 2;
|
||||
|
||||
private static DolbyUtils mInstance;
|
||||
private DolbyAtmos mDolbyAtmos;
|
||||
private Context mContext;
|
||||
private AudioManager mAudioManager;
|
||||
private Handler mHandler = new Handler();
|
||||
private boolean mCallbacksRegistered = false;
|
||||
|
||||
// Restore current profile on every media session
|
||||
private final AudioPlaybackCallback mPlaybackCallback = new AudioPlaybackCallback() {
|
||||
@Override
|
||||
public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
|
||||
boolean isPlaying = configs.stream().anyMatch(
|
||||
c -> c.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
|
||||
dlog("onPlaybackConfigChanged isPlaying=" + isPlaying);
|
||||
if (isPlaying)
|
||||
setCurrentProfile();
|
||||
}
|
||||
};
|
||||
|
||||
// Restore current profile on audio device change
|
||||
private final AudioDeviceCallback mAudioDeviceCallback = new AudioDeviceCallback() {
|
||||
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
|
||||
dlog("onAudioDevicesAdded");
|
||||
setCurrentProfile();
|
||||
}
|
||||
|
||||
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
|
||||
dlog("onAudioDevicesRemoved");
|
||||
setCurrentProfile();
|
||||
}
|
||||
};
|
||||
|
||||
private DolbyUtils(Context context) {
|
||||
mContext = context;
|
||||
mDolbyAtmos = new DolbyAtmos(EFFECT_PRIORITY, 0);
|
||||
mAudioManager = context.getSystemService(AudioManager.class);
|
||||
dlog("initalized");
|
||||
}
|
||||
|
||||
public static synchronized DolbyUtils getInstance(Context context) {
|
||||
if (mInstance == null) {
|
||||
mInstance = new DolbyUtils(context);
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
public void onBootCompleted() {
|
||||
dlog("onBootCompleted");
|
||||
|
||||
// Restore current profile now and on certain audio changes.
|
||||
final boolean dsOn = getDsOn();
|
||||
mDolbyAtmos.setEnabled(dsOn);
|
||||
registerCallbacks(dsOn);
|
||||
if (dsOn)
|
||||
setCurrentProfile();
|
||||
}
|
||||
|
||||
private void checkEffect() {
|
||||
if (!mDolbyAtmos.hasControl()) {
|
||||
Log.w(TAG, "lost control, recreating effect");
|
||||
mDolbyAtmos.release();
|
||||
mDolbyAtmos = new DolbyAtmos(EFFECT_PRIORITY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCurrentProfile() {
|
||||
if (!getDsOn()) {
|
||||
dlog("setCurrentProfile: skip, dolby is off");
|
||||
return;
|
||||
}
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
int profile = Integer.parseInt(prefs.getString(
|
||||
DolbySettingsFragment.PREF_PROFILE, "0" /*dynamic*/));
|
||||
setProfile(profile);
|
||||
}
|
||||
|
||||
private void registerCallbacks(boolean register) {
|
||||
dlog("registerCallbacks(" + register + ") mCallbacksRegistered=" + mCallbacksRegistered);
|
||||
if (register && !mCallbacksRegistered) {
|
||||
mAudioManager.registerAudioPlaybackCallback(mPlaybackCallback, mHandler);
|
||||
mAudioManager.registerAudioDeviceCallback(mAudioDeviceCallback, mHandler);
|
||||
mCallbacksRegistered = true;
|
||||
} else if (!register && mCallbacksRegistered) {
|
||||
mAudioManager.unregisterAudioPlaybackCallback(mPlaybackCallback);
|
||||
mAudioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
|
||||
mCallbacksRegistered = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDsOn(boolean on) {
|
||||
checkEffect();
|
||||
dlog("setDsOn: " + on);
|
||||
mDolbyAtmos.setDsOn(on);
|
||||
registerCallbacks(on);
|
||||
if (on)
|
||||
setCurrentProfile();
|
||||
}
|
||||
|
||||
public boolean getDsOn() {
|
||||
boolean on = mDolbyAtmos.getDsOn();
|
||||
dlog("getDsOn: " + on);
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setProfile(int index) {
|
||||
checkEffect();
|
||||
dlog("setProfile: " + index);
|
||||
mDolbyAtmos.setProfile(index);
|
||||
}
|
||||
|
||||
public int getProfile() {
|
||||
int profile = mDolbyAtmos.getProfile();
|
||||
dlog("getProfile: " + profile);
|
||||
return profile;
|
||||
}
|
||||
|
||||
public String getProfileName() {
|
||||
String profile = Integer.toString(mDolbyAtmos.getProfile());
|
||||
List<String> profiles = Arrays.asList(mContext.getResources().getStringArray(
|
||||
R.array.dolby_profile_values));
|
||||
int profileIndex = profiles.indexOf(profile);
|
||||
dlog("getProfileName: profile=" + profile + " index=" + profileIndex);
|
||||
return profileIndex == -1 ? null : mContext.getResources().getStringArray(
|
||||
R.array.dolby_profile_entries)[profileIndex];
|
||||
}
|
||||
|
||||
public void resetProfileSpecificSettings() {
|
||||
checkEffect();
|
||||
mDolbyAtmos.resetProfileSpecificSettings();
|
||||
}
|
||||
|
||||
public void setPreset(String preset) {
|
||||
checkEffect();
|
||||
int[] gains = Arrays.stream(preset.split(",")).mapToInt(Integer::parseInt).toArray();
|
||||
dlog("setPreset: " + Arrays.toString(gains));
|
||||
mDolbyAtmos.setDapParameter(DsParam.GEQ_BAND_GAINS, gains);
|
||||
}
|
||||
|
||||
public String getPreset() {
|
||||
int[] gains = mDolbyAtmos.getDapParameter(DsParam.GEQ_BAND_GAINS);
|
||||
dlog("getPreset: " + Arrays.toString(gains));
|
||||
String[] preset = Arrays.stream(gains).mapToObj(String::valueOf).toArray(String[]::new);
|
||||
return String.join(",", preset);
|
||||
}
|
||||
|
||||
public void setHeadphoneVirtualizerEnabled(boolean enable) {
|
||||
checkEffect();
|
||||
dlog("setHeadphoneVirtualizerEnabled: " + enable);
|
||||
mDolbyAtmos.setDapParameterBool(DsParam.HEADPHONE_VIRTUALIZER, enable);
|
||||
}
|
||||
|
||||
public boolean getHeadphoneVirtualizerEnabled() {
|
||||
boolean enabled = mDolbyAtmos.getDapParameterBool(DsParam.HEADPHONE_VIRTUALIZER);
|
||||
dlog("getHeadphoneVirtualizerEnabled: " + enabled);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setSpeakerVirtualizerEnabled(boolean enable) {
|
||||
checkEffect();
|
||||
dlog("setSpeakerVirtualizerEnabled: " + enable);
|
||||
mDolbyAtmos.setDapParameterBool(DsParam.SPEAKER_VIRTUALIZER, enable);
|
||||
}
|
||||
|
||||
public boolean getSpeakerVirtualizerEnabled() {
|
||||
boolean enabled = mDolbyAtmos.getDapParameterBool(DsParam.SPEAKER_VIRTUALIZER);
|
||||
dlog("getSpeakerVirtualizerEnabled: " + enabled);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setStereoWideningAmount(int amount) {
|
||||
checkEffect();
|
||||
dlog("setStereoWideningAmount: " + amount);
|
||||
mDolbyAtmos.setDapParameterInt(DsParam.STEREO_WIDENING_AMOUNT, amount);
|
||||
}
|
||||
|
||||
public int getStereoWideningAmount() {
|
||||
int amount = mDolbyAtmos.getDapParameterInt(DsParam.STEREO_WIDENING_AMOUNT);
|
||||
dlog("getStereoWideningAmount: " + amount);
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setDialogueEnhancerAmount(int amount) {
|
||||
checkEffect();
|
||||
dlog("setDialogueEnhancerAmount: " + amount);
|
||||
mDolbyAtmos.setDapParameterBool(DsParam.DIALOGUE_ENHANCER_ENABLE, amount > 0);
|
||||
mDolbyAtmos.setDapParameterInt(DsParam.DIALOGUE_ENHANCER_AMOUNT, amount);
|
||||
}
|
||||
|
||||
public int getDialogueEnhancerAmount() {
|
||||
boolean enabled = mDolbyAtmos.getDapParameterBool(
|
||||
DsParam.DIALOGUE_ENHANCER_ENABLE);
|
||||
int amount = enabled ? mDolbyAtmos.getDapParameterInt(
|
||||
DsParam.DIALOGUE_ENHANCER_AMOUNT) : 0;
|
||||
dlog("getDialogueEnhancerAmount: " + enabled + " amount=" + amount);
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setBassEnhancerEnabled(boolean enable) {
|
||||
checkEffect();
|
||||
dlog("setBassEnhancerEnabled: " + enable);
|
||||
mDolbyAtmos.setDapParameterBool(DsParam.BASS_ENHANCER_ENABLE, enable);
|
||||
}
|
||||
|
||||
public boolean getBassEnhancerEnabled() {
|
||||
boolean enabled = mDolbyAtmos.getDapParameterBool(DsParam.BASS_ENHANCER_ENABLE);
|
||||
dlog("getBassEnhancerEnabled: " + enabled);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setVolumeLevelerEnabled(boolean enable) {
|
||||
checkEffect();
|
||||
dlog("setVolumeLevelerEnabled: " + enable);
|
||||
mDolbyAtmos.setDapParameterBool(DsParam.VOLUME_LEVELER_ENABLE, enable);
|
||||
mDolbyAtmos.setDapParameterInt(DsParam.VOLUME_LEVELER_AMOUNT,
|
||||
enable ? VOLUME_LEVELER_AMOUNT : 0);
|
||||
}
|
||||
|
||||
public boolean getVolumeLevelerEnabled() {
|
||||
boolean enabled = mDolbyAtmos.getDapParameterBool(DsParam.VOLUME_LEVELER_ENABLE);
|
||||
int amount = mDolbyAtmos.getDapParameterInt(DsParam.VOLUME_LEVELER_AMOUNT);
|
||||
dlog("getVolumeLevelerEnabled: " + enabled + " amount=" + amount);
|
||||
return enabled && (amount == VOLUME_LEVELER_AMOUNT);
|
||||
}
|
||||
|
||||
private static void dlog(String msg) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
* (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi;
|
||||
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import co.aospa.dolby.xiaomi.R;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/** Provide preference summary for injected items. */
|
||||
public class SummaryProvider extends ContentProvider {
|
||||
|
||||
private static final String KEY_DOLBY = "dolby";
|
||||
|
||||
@Override
|
||||
public Bundle call(String method, String uri, Bundle extras) {
|
||||
final Bundle bundle = new Bundle();
|
||||
String summary;
|
||||
switch (method) {
|
||||
case KEY_DOLBY:
|
||||
summary = getDolbySummary();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown method: " + method);
|
||||
}
|
||||
bundle.putString(META_DATA_PREFERENCE_SUMMARY, summary);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
|
||||
String sortOrder) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private String getDolbySummary() {
|
||||
final DolbyUtils dolbyUtils = DolbyUtils.getInstance(getContext());
|
||||
final boolean dsOn = dolbyUtils.getDsOn();
|
||||
if (!dsOn) {
|
||||
return getContext().getString(R.string.dolby_off);
|
||||
}
|
||||
final String profileName = dolbyUtils.getProfileName();
|
||||
if (profileName == null) {
|
||||
return getContext().getString(R.string.dolby_on);
|
||||
} else {
|
||||
return getContext().getString(R.string.dolby_on_with_profile, profileName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
70
dolby/src/co/aospa/dolby/xiaomi/SummaryProvider.kt
Normal file
70
dolby/src/co/aospa/dolby/xiaomi/SummaryProvider.kt
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
* (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.xiaomi
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import co.aospa.dolby.xiaomi.R
|
||||
import com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY
|
||||
|
||||
private const val KEY_DOLBY = "dolby"
|
||||
|
||||
/** Provide preference summary for injected items. */
|
||||
class SummaryProvider : ContentProvider() {
|
||||
|
||||
override fun call(
|
||||
method: String,
|
||||
arg: String?,
|
||||
extras: Bundle?
|
||||
): Bundle? {
|
||||
val summary = when (method) {
|
||||
KEY_DOLBY -> getDolbySummary()
|
||||
else -> return null
|
||||
}
|
||||
return Bundle().apply {
|
||||
putString(META_DATA_PREFERENCE_SUMMARY, summary)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(): Boolean = true
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<String>?,
|
||||
sortOrder: String?
|
||||
): Cursor? = null
|
||||
|
||||
override fun getType(uri: Uri): String? = null
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<String>?
|
||||
): Int = 0
|
||||
|
||||
private fun getDolbySummary(): String {
|
||||
val dolbyController = DolbyController.getInstance(context)
|
||||
if (!dolbyController.dsOn) {
|
||||
return context.getString(R.string.dolby_off)
|
||||
}
|
||||
return dolbyController.getProfileName()?.let {
|
||||
context.getString(R.string.dolby_on_with_profile, it)
|
||||
} ?: context.getString(R.string.dolby_on)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user