diff --git a/app/build.gradle b/app/build.gradle
index f442a4c..c830a91 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -12,7 +12,7 @@ android {
minSdk 27
targetSdk 34
versionCode 1
- versionName "1.4.0"
+ versionName "1.4.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/app/release/app-release.apk b/app/release/app-release.apk
index 025ca9c..5f40095 100644
Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index 55e55be..559cf10 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -12,7 +12,7 @@
"filters": [],
"attributes": [],
"versionCode": 1,
- "versionName": "1.4.0",
+ "versionName": "1.4.1",
"outputFile": "app-release.apk"
}
],
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ad0ea1c..e868867 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,7 +7,7 @@
-
+
+
(R.id.apps_list)
+ list = findViewById(R.id.apps_list)
ShizukuRunner.runAdbCommand("pm grant $packageName android.permission.QUERY_ALL_PACKAGES",
object : ShizukuRunner.CommandResultListener {
override fun onCommandResult(output: String, done: Boolean) {}
diff --git a/app/src/main/java/com/legendsayantan/adbtools/MainActivity.kt b/app/src/main/java/com/legendsayantan/adbtools/MainActivity.kt
index 6ed5b82..e6e607f 100644
--- a/app/src/main/java/com/legendsayantan/adbtools/MainActivity.kt
+++ b/app/src/main/java/com/legendsayantan/adbtools/MainActivity.kt
@@ -29,6 +29,7 @@ import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import com.legendsayantan.adbtools.lib.ShizukuRunner
import com.legendsayantan.adbtools.lib.Utils.Companion.initialiseStatusBar
+import com.legendsayantan.adbtools.services.SoundMasterService
import java.util.UUID
/**
* @author legendsayantan
@@ -92,6 +93,7 @@ class MainActivity : AppCompatActivity() {
//create notification
val intent = Intent(this, SoundMasterActivity::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ SoundMasterService.uiIntent = intent
val channelId = "notifications"
val notificationBuilder = NotificationCompat.Builder(applicationContext, channelId)
.setSmallIcon(R.drawable.outline_info_24)
diff --git a/app/src/main/java/com/legendsayantan/adbtools/SoundMasterActivity.kt b/app/src/main/java/com/legendsayantan/adbtools/SoundMasterActivity.kt
index 454c68c..303dbe8 100644
--- a/app/src/main/java/com/legendsayantan/adbtools/SoundMasterActivity.kt
+++ b/app/src/main/java/com/legendsayantan/adbtools/SoundMasterActivity.kt
@@ -6,7 +6,7 @@ import android.content.Context
import android.content.Intent
import android.media.projection.MediaProjectionManager
import android.os.Bundle
-import android.view.Gravity
+import android.os.Handler
import android.view.View
import android.view.WindowManager
import android.widget.ImageView
@@ -56,16 +56,20 @@ class SoundMasterActivity : AppCompatActivity() {
@SuppressLint("ApplySharedPref")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ showing = true
setContentView(R.layout.activity_sound_master)
initialiseStatusBar()
+ interacted()
//new slider
findViewById(R.id.newSlider).setOnClickListener {
+ lastInteractionAt = -1
NewSliderDialog(this@SoundMasterActivity) { pkg ->
val newPackages = packages
newPackages.add(pkg)
packages = newPackages
if (SoundMasterService.running) SoundMasterService.onDynamicAttach(pkg)
updateSliders()
+ interacted()
}.show()
}
@@ -79,6 +83,18 @@ class SoundMasterActivity : AppCompatActivity() {
findViewById(R.id.main).setOnClickListener {
finish()
}
+
+ setupAutoHide()
+ }
+
+ private fun setupAutoHide(){
+ Timer().schedule(timerTask {
+ if (lastInteractionAt>=0
+ && lastInteractionAt+hideTimerInterval < System.currentTimeMillis()) {
+ finish()
+ cancel()
+ }
+ }, hideTimerInterval,hideTimerInterval)
}
override fun onResume() {
@@ -100,8 +116,7 @@ class SoundMasterActivity : AppCompatActivity() {
applicationContext,
"No apps selected to control",
Toast.LENGTH_SHORT
- )
- .show()
+ ).show()
} else {
ShizukuRunner.runAdbCommand("pm grant ${baseContext.packageName} android.permission.RECORD_AUDIO",
object : ShizukuRunner.CommandResultListener {
@@ -125,6 +140,12 @@ class SoundMasterActivity : AppCompatActivity() {
})
}
}
+
+ override fun onCommandError(error: String) {
+ Handler(mainLooper).post {
+ Toast.makeText(applicationContext,"Shizuku Error", Toast.LENGTH_SHORT).show()
+ }
+ }
})
}
}
@@ -136,6 +157,7 @@ class SoundMasterActivity : AppCompatActivity() {
cancel()
} else count++
if (count > 50) cancel()
+ interacted()
}, 500, 500)
}
}
@@ -153,16 +175,24 @@ class SoundMasterActivity : AppCompatActivity() {
startService(Intent(this, SoundMasterService::class.java).apply {
putExtra("packages", packages.toTypedArray())
})
+ interacted()
} else {
Toast.makeText(
this, "Request to obtain MediaProjection denied.",
Toast.LENGTH_SHORT
).show()
+ interacted()
}
}
}
+ override fun finish() {
+ showing = false
+ super.finish()
+ }
+
private fun updateSliders() {
+ interacted()
findViewById(R.id.none).visibility =
if (packages.size > 0) View.GONE else View.VISIBLE
Thread {
@@ -173,17 +203,21 @@ class SoundMasterActivity : AppCompatActivity() {
}
val adapter =
VolumeBarAdapter(this@SoundMasterActivity, sliderMap, { app, vol ->
+ interacted()
SoundMasterService.setVolumeOf(app, vol)
}, {
+ interacted()
val newPackages = packages
newPackages.remove(it)
packages = newPackages
updateSliders()
SoundMasterService.onDynamicDetach(it)
}, { app, sliderIndex ->
+ interacted()
if (sliderIndex == 0) SoundMasterService.getBalanceOf(app)
else SoundMasterService.getBandValueOf(app, sliderIndex - 1)
}, { app, slider, value ->
+ interacted()
if (slider == 0) SoundMasterService.setBalanceOf(app, value)
else SoundMasterService.setBandValueOf(app, slider - 1, value)
})
@@ -195,6 +229,12 @@ class SoundMasterActivity : AppCompatActivity() {
}
companion object {
+ var showing = false
+ private const val hideTimerInterval = 2000L
+ var lastInteractionAt = 0L
+ var interacted = {
+ lastInteractionAt = System.currentTimeMillis()
+ }
private const val FILENAME_SOUNDMASTER = "soundmaster.txt"
private const val MEDIA_PROJECTION_REQUEST_CODE = 13
}
diff --git a/app/src/main/java/com/legendsayantan/adbtools/lib/ShizukuRunner.kt b/app/src/main/java/com/legendsayantan/adbtools/lib/ShizukuRunner.kt
index d5e170a..c0dbff3 100644
--- a/app/src/main/java/com/legendsayantan/adbtools/lib/ShizukuRunner.kt
+++ b/app/src/main/java/com/legendsayantan/adbtools/lib/ShizukuRunner.kt
@@ -10,27 +10,33 @@ import java.io.InputStreamReader
class ShizukuRunner {
interface CommandResultListener {
fun onCommandResult(output: String, done:Boolean)
+ fun onCommandError(error: String){}
}
companion object {
fun runAdbCommand(command: String, listener: CommandResultListener) {
Thread {
- val process = Shizuku.newProcess(arrayOf("sh", "-c", command), null, "/")
- val reader = BufferedReader(InputStreamReader(process.inputStream))
- val output = StringBuilder()
+ try{
+ val process = Shizuku.newProcess(arrayOf("sh", "-c", command), null, "/")
+ val reader = BufferedReader(InputStreamReader(process.inputStream))
+ val output = StringBuilder()
- var line: String?
- var linecount = 0
- while (reader.readLine().also { line = it } != null) {
- linecount++
- output.append(line).append("\n")
- if (linecount == 50) {
- linecount = 0
- listener.onCommandResult(output.toString(),false)
+ var line: String?
+ var linecount = 0
+ while (reader.readLine().also { line = it } != null) {
+ linecount++
+ output.append(line).append("\n")
+ if (linecount == 50) {
+ linecount = 0
+ listener.onCommandResult(output.toString(),false)
+ }
}
+ listener.onCommandResult(output.toString(),true)
+ process.waitFor()
+ }catch (e:Exception){
+ listener.onCommandError(e.message?:"No Shizuku")
}
- listener.onCommandResult(output.toString(),true)
- process.waitFor()
+
}.start()
}
}
diff --git a/app/src/main/java/com/legendsayantan/adbtools/services/AudioThread.kt b/app/src/main/java/com/legendsayantan/adbtools/services/AudioThread.kt
index bef1365..874a82b 100644
--- a/app/src/main/java/com/legendsayantan/adbtools/services/AudioThread.kt
+++ b/app/src/main/java/com/legendsayantan/adbtools/services/AudioThread.kt
@@ -14,7 +14,9 @@ import android.media.audiofx.LoudnessEnhancer
import android.media.audiofx.NoiseSuppressor
import android.media.projection.MediaProjection
import android.os.Build
+import android.os.Handler
import android.util.Log
+import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import com.legendsayantan.adbtools.lib.ShizukuRunner
@@ -24,32 +26,48 @@ import com.legendsayantan.adbtools.services.SoundMasterService.Companion.CHANNEL
import com.legendsayantan.adbtools.services.SoundMasterService.Companion.LOG_TAG
import com.legendsayantan.adbtools.services.SoundMasterService.Companion.SAMPLE_RATE
import com.legendsayantan.adbtools.services.SoundMasterService.Companion.bandDivision
+import com.legendsayantan.adbtools.services.SoundMasterService.Companion.notiUpdateTime
+import com.legendsayantan.adbtools.services.SoundMasterService.Companion.zeroByte
/**
* @author legendsayantan
*/
-class AudioThread(val context: Context, val pkg:String, private val mediaProjection: MediaProjection) : Thread() {
+class AudioThread(
+ val context: Context,
+ val pkg: String,
+ private val mediaProjection: MediaProjection
+) : Thread("$LOG_TAG : $pkg") {
var playback = true
- var volume : Float = 1f
- var targetVolume : Float = 100f
+ var volume: Float = 1f
+ var targetVolume: Float = 100f
val dataBuffer = ByteArray(BUF_SIZE)
- private var stereoGainFactor = arrayOf(1f,1f)
+ lateinit var monitorThread : Thread
+ var loadedCycles = 0
+ var latencyUpdate:(Int)->Unit = {}
+ private var stereoGainFactor = arrayOf(1f, 1f)
private var bandCompensations = arrayOf(0, 0, 0)
val equalizer by lazy { Equalizer(0, mTrack.audioSessionId) }
- val enhancer by lazy {LoudnessEnhancer(mTrack.audioSessionId)}
- val suppress by lazy {NoiseSuppressor.create(mTrack.audioSessionId)}
- val echoCancel by lazy {AcousticEchoCanceler.create(mTrack.audioSessionId)}
+ val enhancer by lazy { LoudnessEnhancer(mTrack.audioSessionId) }
+ val suppress by lazy { NoiseSuppressor.create(mTrack.audioSessionId) }
+ val echoCancel by lazy { AcousticEchoCanceler.create(mTrack.audioSessionId) }
lateinit var mRecord: AudioRecord
- lateinit var mTrack : AudioTrack
- var savedBands = arrayOf(50f,50f,50f)
+ lateinit var mTrack: AudioTrack
+ var savedBands = arrayOf(50f, 50f, 50f)
override fun start() {
- ShizukuRunner.runAdbCommand("appops set $pkg PLAY_AUDIO deny",object : ShizukuRunner.CommandResultListener{
- override fun onCommandResult(output: String, done: Boolean) {}
- })
+ ShizukuRunner.runAdbCommand("appops set $pkg PLAY_AUDIO deny",
+ object : ShizukuRunner.CommandResultListener {
+ override fun onCommandResult(output: String, done: Boolean) {}
+ override fun onCommandError(error: String) {
+ Handler(context.mainLooper).post {
+ Toast.makeText(context,"Shizuku Error", Toast.LENGTH_SHORT).show()
+ }
+ }
+ })
super.start()
}
+
@RequiresApi(Build.VERSION_CODES.Q)
override fun run() {
if (ActivityCompat.checkSelfPermission(
@@ -60,7 +78,6 @@ class AudioThread(val context: Context, val pkg:String, private val mediaProject
interrupt()
return
}
-
try {
val config = AudioPlaybackCaptureConfiguration.Builder(mediaProjection)
.addMatchingUsage(AudioAttributes.USAGE_MEDIA)
@@ -119,13 +136,14 @@ class AudioThread(val context: Context, val pkg:String, private val mediaProject
while (playback) {
mRecord.read(dataBuffer, 0, BUF_SIZE)
mTrack.write(dataBuffer, 0, dataBuffer.size)
+ loadedCycles++
}
- }catch (e:Exception){
- Log.e(LOG_TAG,"Error in VolumeThread: ${e.message}")
+ } catch (e: Exception) {
+ Log.e(LOG_TAG, "Error in VolumeThread: ${e.message}")
}
}
- fun setCurrentVolume(it:Float){
+ fun setCurrentVolume(it: Float) {
volume = (it / 100f).coerceAtMost(1f)
mTrack.setStereoVolume(volume * stereoGainFactor[0], volume * stereoGainFactor[1])
try {
@@ -150,7 +168,7 @@ class AudioThread(val context: Context, val pkg:String, private val mediaProject
return (100 - (stereoGainFactor[0] * 100).toInt()) - (100 - (stereoGainFactor[1] * 100))
}
- fun setBalance(value:Float){
+ fun setBalance(value: Float) {
stereoGainFactor = arrayOf(
if (value <= 0) 1f else 1f - (value / 100f),
if (value >= 0) 1f else 1f + (value / 100f)
@@ -158,7 +176,7 @@ class AudioThread(val context: Context, val pkg:String, private val mediaProject
mTrack.setStereoVolume(volume * stereoGainFactor[0], volume * stereoGainFactor[1])
}
- fun setBand(band:Int,value:Float){
+ fun setBand(band: Int, value: Float) {
savedBands[band] = value
updateBandLevel(band, value)
}
@@ -189,16 +207,30 @@ class AudioThread(val context: Context, val pkg:String, private val mediaProject
}
}
+ fun getLatency(): Float {
+ return notiUpdateTime.toFloat()/loadedCycles.coerceAtLeast(1).also { loadedCycles=0 }
+ }
+
override fun interrupt() {
playback = false
- ShizukuRunner.runAdbCommand("appops set $pkg PLAY_AUDIO allow",object : ShizukuRunner.CommandResultListener{
- override fun onCommandResult(output: String, done: Boolean) {}
- })
+ ShizukuRunner.runAdbCommand("appops set $pkg PLAY_AUDIO allow",
+ object : ShizukuRunner.CommandResultListener {
+ override fun onCommandResult(output: String, done: Boolean) {}
+ override fun onCommandError(error: String) {
+ Handler(context.mainLooper).post {
+ Toast.makeText(context,"Shizuku Error", Toast.LENGTH_SHORT).show()
+ }
+ }
+ })
mRecord.stop()
mRecord.release()
mTrack.stop()
mTrack.release()
+ try{
+ monitorThread.interrupt()
+ }catch (_:Exception){
+
+ }
super.interrupt()
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/legendsayantan/adbtools/services/SoundMasterService.kt b/app/src/main/java/com/legendsayantan/adbtools/services/SoundMasterService.kt
index c96001d..a7b828f 100644
--- a/app/src/main/java/com/legendsayantan/adbtools/services/SoundMasterService.kt
+++ b/app/src/main/java/com/legendsayantan/adbtools/services/SoundMasterService.kt
@@ -1,24 +1,51 @@
package com.legendsayantan.adbtools.services
+import android.Manifest
import android.app.Activity
import android.app.Service
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.content.pm.ServiceInfo
+import android.database.ContentObserver
import android.media.AudioFormat
+import android.media.AudioManager
import android.media.AudioRecord
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.os.Build
+import android.os.Handler
import android.os.IBinder
+import android.provider.Settings
+import android.util.Log
+import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.core.content.PackageManagerCompat
import com.legendsayantan.adbtools.R
+import com.legendsayantan.adbtools.SoundMasterActivity
+import com.legendsayantan.adbtools.lib.ShizukuRunner
+import java.lang.Byte
+import java.util.Timer
+import kotlin.Boolean
+import kotlin.Float
+import kotlin.Int
+import kotlin.String
+import kotlin.Unit
+import kotlin.arrayOf
+import kotlin.concurrent.timerTask
+import kotlin.let
+
class SoundMasterService : Service() {
+ private lateinit var mVolumeObserver: ContentObserver
+ private val audioManager by lazy { getSystemService(Context.AUDIO_SERVICE) as AudioManager }
private var mediaProjectionManager: MediaProjectionManager? = null
private var mediaProjection: MediaProjection? = null
var threadMap = hashMapOf()
var apps = mutableListOf()
+ var latency = mutableListOf(0)
+ var latencyUpdateTimer = Timer()
override fun onBind(intent: Intent): IBinder {
return null!!
}
@@ -27,18 +54,38 @@ class SoundMasterService : Service() {
super.onCreate()
//foreground service
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- val notification = NotificationCompat.Builder(this, "notifications")
- .setContentTitle(applicationContext.getString(R.string.soundmaster)+" is controlling apps.")
- .setSmallIcon(R.drawable.ic_launcher_foreground)
- .setPriority(NotificationCompat.PRIORITY_LOW)
- .build()
- startForeground(
- 1,
- notification,
- ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
- )
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+ return
}
+
+ val builder = NotificationCompat.Builder(this, "notifications")
+ .setContentText("You can change volume to configure ${applicationContext.getString(R.string.soundmaster)} as well.")
+ .setSmallIcon(R.drawable.ic_launcher_foreground)
+ .setPriority(NotificationCompat.PRIORITY_LOW)
+ .setOnlyAlertOnce(true)
+ startForeground(
+ NOTI_ID,
+ builder.build(),
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
+ )
+ latencyUpdateTimer.schedule(timerTask {
+ val avg = threadMap.values.map { it.getLatency() }.average().toInt()
+ threadMap.values.forEach { it.loadedCycles = 0 }
+ builder.setContentTitle(applicationContext.getString(R.string.soundmaster) + " is controlling ${apps.size} apps.")
+ builder.setContentText("Average Latency: $avg ms")
+ latency.clear()
+ if (ActivityCompat.checkSelfPermission(
+ applicationContext,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ NotificationManagerCompat.from(applicationContext)
+ .notify(NOTI_ID, builder.build())
+ }
+ }, notiUpdateTime, notiUpdateTime)
+
+ initVolumeBtnControl()
+
mediaProjectionManager =
applicationContext.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
@@ -56,28 +103,32 @@ class SoundMasterService : Service() {
threadMap[it]?.getBalance() ?: 0f
}
- setBalanceOf = {it,value->
+ setBalanceOf = { it, value ->
threadMap[it]?.setBalance(value)
}
- getBandValueOf = {it,band->
+ getBandValueOf = { it, band ->
threadMap[it]?.savedBands?.get(band) ?: 50f
}
- setBandValueOf = { it,band,value->
- threadMap[it]?.setBand(band,value)
+ setBandValueOf = { it, band, value ->
+ threadMap[it]?.setBand(band, value)
}
- onDynamicAttach = {
- if (!apps.contains(it)) {
- apps += it
+ onDynamicAttach = { it ->
+ if (!threadMap.contains(it)) {
+ if (!apps.contains(it)) apps.add(it)
val mThread = AudioThread(applicationContext, it, mediaProjection!!)
+ mThread.targetVolume = volumeTemp[it] ?: 100f
+ mThread.latencyUpdate = { value ->
+ latency.add(value)
+ }
threadMap[it] = mThread
mThread.start()
}
}
- onDynamicDetach = { pkg->
+ onDynamicDetach = { pkg ->
if (apps.contains(pkg)) {
apps.remove(pkg)
threadMap[pkg]?.interrupt()
@@ -96,19 +147,40 @@ class SoundMasterService : Service() {
projectionData!!
) as MediaProjection
apps.forEach {
- val mThread = AudioThread(applicationContext, it, mediaProjection!!).apply {
- targetVolume = volumeTemp[it]?:100f
- }
- threadMap[it] = mThread
- mThread.start()
+ onDynamicAttach(it)
}
}
}
return START_STICKY
}
+ private fun initVolumeBtnControl() {
+ mVolumeObserver = object : ContentObserver(Handler(mainLooper)) {
+ var prevVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
+ override fun onChange(selfChange: Boolean) {
+ super.onChange(selfChange)
+ val newVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
+ if(newVolume != prevVolume){
+ prevVolume = newVolume
+ Handler(mainLooper).post {
+ if(SoundMasterActivity.showing) SoundMasterActivity.interacted()
+ else ShizukuRunner.runAdbCommand("am start -n $packageName/${SoundMasterActivity::class.java.canonicalName}",object : ShizukuRunner.CommandResultListener{
+ override fun onCommandResult(output: String, done: Boolean) {}
+ })
+ }
+ }
+ }
+ }
+ contentResolver.registerContentObserver(
+ Settings.System.CONTENT_URI, true,
+ mVolumeObserver
+ )
+ }
+
override fun onDestroy() {
running = false
+ contentResolver.unregisterContentObserver(mVolumeObserver)
+ latencyUpdateTimer.cancel()
threadMap.forEach { it.value.interrupt() }
mediaProjection?.stop()
super.onDestroy()
@@ -121,20 +193,23 @@ class SoundMasterService : Service() {
var onDynamicDetach: (String) -> Unit = {}
var volumeTemp = HashMap()
var setVolumeOf: (String, Float) -> Unit = { a, b -> volumeTemp[a] = b }
- var getVolumeOf: (String) -> Float = { p -> volumeTemp[p]?:100f }
- var setBalanceOf: (String, Float) -> Unit = { a, b -> }
- var getBalanceOf: (String) -> Float = {_->0f}
- var setBandValueOf: (String,Int,Float) ->Unit = {_,_,_->}
- var getBandValueOf:(String,Int)->Float = {_,_-> 50f}
-
+ var getVolumeOf: (String) -> Float = { p -> volumeTemp[p] ?: 100f }
+ var setBalanceOf: (String, Float) -> Unit = { a, b -> }
+ var getBalanceOf: (String) -> Float = { _ -> 0f }
+ var setBandValueOf: (String, Int, Float) -> Unit = { _, _, _ -> }
+ var getBandValueOf: (String, Int) -> Float = { _, _ -> 50f }
+
+ const val NOTI_ID = 1
+ const val notiUpdateTime = 30000L
const val SAMPLE_RATE = 44100
const val LOG_TAG = "SoundMaster"
const val CHANNEL = AudioFormat.CHANNEL_IN_STEREO
val BUF_SIZE =
AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL, AudioFormat.ENCODING_PCM_16BIT)
+ val zeroByte = Byte.valueOf(0)
val bandDivision = arrayOf(0, 250, 2000, 20000)
+ lateinit var uiIntent: Intent
}
-
}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bc7ec78..8cec1da 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,4 +1,4 @@
-
+
ShizuTools
This app requires Shizuku.\nPlease make sure you have shizuku installed and running.
Force applying MixedAudio may crash some apps, and doing so on system apps may crash your entire system.
@@ -37,4 +37,5 @@
Low Bands
Mid Bands
High Bands
+ getevent -q
\ No newline at end of file