diff --git a/README.md b/README.md index 251a1bc..67d871f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # VolumeLockr VolumeLockr allows you to control your Android device volume levels and set locks for each one of them. -

  

+

  

## Installation You can either download it from F-Droid or build it manually. diff --git a/app/build.gradle b/app/build.gradle index dd45cab..a29f530 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,20 +1,21 @@ plugins { id 'com.android.application' - id 'org.jetbrains.kotlin.kapt' + id 'org.jetbrains.kotlin.kapt' apply false id 'kotlin-android' id 'com.mikepenz.aboutlibraries.plugin' } android { - compileSdkVersion 31 + compileSdk 34 buildToolsVersion "30.0.3" defaultConfig { applicationId "com.klee.volumelockr" - minSdkVersion 16 - targetSdkVersion 31 - versionCode 9 - versionName "1.5.0" + minSdkVersion 19 + targetSdkVersion 34 + versionCode 11 + versionName "1.6.1" + multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -36,6 +37,7 @@ android { buildFeatures { viewBinding true } + namespace 'com.klee.volumelockr' } dependencies { @@ -43,7 +45,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' - implementation 'com.google.android.material:material:1.5.0' + implementation 'com.google.android.material:material:1.12.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1bfbc50..c8d3816 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,10 +1,11 @@ - + + + + android:theme="@style/Theme.VolumeLockr"> - + = Build.VERSION_CODES.JELLY_BEAN_MR1) { - mMode = Settings.Global.getInt(contentResolver, MODE_RINGER_SETTING) - } + mMode = Settings.Global.getInt(contentResolver, MODE_RINGER_SETTING) registerObservers() @@ -95,9 +98,7 @@ class VolumeService : Service() { } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) - mAllowLower = sharedPreferences.getBoolean(ALLOW_LOWER, false) - + loadGeneralPreferences() return START_STICKY } @@ -162,12 +163,13 @@ class VolumeService : Service() { private fun savePreferences() { val sharedPreferences = getSharedPreferences(APP_SHARED_PREFERENCES, MODE_PRIVATE) - val editor = sharedPreferences.edit() - editor.putString(LOCKS_KEY, Gson().toJson(mVolumeLock)) - editor.apply() + sharedPreferences.edit { + putString(LOCKS_KEY, Gson().toJson(mVolumeLock)) + } } private fun loadPreferences() { + loadGeneralPreferences() val sharedPreferences = getSharedPreferences(APP_SHARED_PREFERENCES, MODE_PRIVATE) class Token : TypeToken>() val value = sharedPreferences.getString(LOCKS_KEY, "") @@ -177,6 +179,11 @@ class VolumeService : Service() { } } + private fun loadGeneralPreferences() { + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) + mAllowLower = sharedPreferences.getBoolean(ALLOW_LOWER, false) + } + @WorkerThread @Synchronized private fun checkVolumes() { @@ -207,9 +214,7 @@ class VolumeService : Service() { override fun onChange(selfChange: Boolean) { super.onChange(selfChange) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - mMode = Settings.Global.getInt(contentResolver, MODE_RINGER_SETTING) - } + mMode = Settings.Global.getInt(contentResolver, MODE_RINGER_SETTING) mModeListener?.invoke() } @@ -233,11 +238,9 @@ class VolumeService : Service() { registerObserver(VOLUME_VOICE_HEADSET_SETTING) registerObserver(VOLUME_VOICE_BT_SETTING) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - contentResolver.registerContentObserver( - Settings.Global.getUriFor(MODE_RINGER_SETTING), true, mModeObserver - ) - } + contentResolver.registerContentObserver( + Settings.Global.getUriFor(MODE_RINGER_SETTING), true, mModeObserver + ) } private fun registerObserver(setting: String) { @@ -248,7 +251,7 @@ class VolumeService : Service() { @Synchronized fun tryShowNotification() { - if (mVolumeLock.size == 0) { + if (mVolumeLock.isEmpty()) { return } @@ -267,7 +270,7 @@ class VolumeService : Service() { @RequiresApi(Build.VERSION_CODES.N) @Synchronized fun tryHideNotification() { - if (mVolumeLock.size > 0) { + if (mVolumeLock.isNotEmpty()) { return } diff --git a/app/src/main/java/com/klee/volumelockr/ui/MainActivity.kt b/app/src/main/java/com/klee/volumelockr/ui/MainActivity.kt index 50c779b..3f6bacb 100644 --- a/app/src/main/java/com/klee/volumelockr/ui/MainActivity.kt +++ b/app/src/main/java/com/klee/volumelockr/ui/MainActivity.kt @@ -3,36 +3,44 @@ package com.klee.volumelockr.ui import android.app.AlertDialog import android.app.Dialog import android.app.NotificationManager -import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.provider.Settings import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import com.klee.volumelockr.R -import com.klee.volumelockr.service.VolumeService class MainActivity : AppCompatActivity() { + companion object { + private const val NOTIFICATION_PERMISSION = "android.permission.POST_NOTIFICATIONS" + private const val PERMISSION_REQUEST_CODE = 25 + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - } - - override fun onResume() { - super.onResume() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkDoNotDisturbPermission() } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (ContextCompat.checkSelfPermission(applicationContext, NOTIFICATION_PERMISSION) + == PackageManager.PERMISSION_DENIED) { + requestPermissions(arrayOf(NOTIFICATION_PERMISSION), PERMISSION_REQUEST_CODE) + } + } } @RequiresApi(Build.VERSION_CODES.M) private fun checkDoNotDisturbPermission() { val notificationManager = - getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + getSystemService(NOTIFICATION_SERVICE) as NotificationManager if (!notificationManager.isNotificationPolicyAccessGranted) { PolicyAccessDialog().show(supportFragmentManager, PolicyAccessDialog.TAG) diff --git a/app/src/main/java/com/klee/volumelockr/ui/VolumeAdapter.kt b/app/src/main/java/com/klee/volumelockr/ui/VolumeAdapter.kt index 731d562..3d7ef03 100644 --- a/app/src/main/java/com/klee/volumelockr/ui/VolumeAdapter.kt +++ b/app/src/main/java/com/klee/volumelockr/ui/VolumeAdapter.kt @@ -5,10 +5,10 @@ import android.media.AudioManager import android.os.Build import android.view.LayoutInflater import android.view.ViewGroup -import android.widget.SeekBar import androidx.annotation.MainThread import androidx.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.slider.Slider import com.klee.volumelockr.databinding.VolumeCardBinding import com.klee.volumelockr.service.VolumeService import com.klee.volumelockr.ui.SettingsFragment @@ -44,11 +44,9 @@ class VolumeAdapter( override fun onBindViewHolder(holder: ViewHolder, position: Int) { val volume = mVolumeList[position] holder.binding.mediaTextView.text = volume.name - holder.binding.seekBar.progress = mService?.getLocks()?.get(volume.stream) ?: volume.value - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - holder.binding.seekBar.min = volume.min - } - holder.binding.seekBar.max = volume.max + holder.binding.slider.value = mService?.getLocks()?.get(volume.stream)?.toFloat() ?: volume.value.toFloat() + holder.binding.slider.valueFrom = volume.min.toFloat() + holder.binding.slider.valueTo = volume.max.toFloat() registerSeekBarCallback(holder, volume) registerSwitchButtonCallback(holder, volume) @@ -58,28 +56,21 @@ class VolumeAdapter( handleRingerMode(holder, volume) if (isPasswordProtected()) { - holder.binding.seekBar.isEnabled = false + holder.binding.slider.isEnabled = false holder.binding.switchButton.isEnabled = false } } private fun registerSeekBarCallback(holder: ViewHolder, volume: Volume) { - val listener = object : SeekBar.OnSeekBarChangeListener { - override fun onProgressChanged(view: SeekBar?, progress: Int, fromUser: Boolean) { + val listener = + Slider.OnChangeListener { _, value, _ -> if (volume.stream != AudioManager.STREAM_NOTIFICATION || mService?.getMode() == 2) { - mAudioManager.setStreamVolume(volume.stream, progress, 0) + mAudioManager.setStreamVolume(volume.stream, value.toInt(), 0) } - volume.value = progress - } - - override fun onStartTrackingTouch(view: SeekBar?) { + volume.value = value.toInt() } - - override fun onStopTrackingTouch(view: SeekBar?) { - } - } - holder.binding.seekBar.setOnSeekBarChangeListener(listener) + holder.binding.slider.addOnChangeListener(listener) } private fun registerSwitchButtonCallback(holder: ViewHolder, volume: Volume) { @@ -98,7 +89,7 @@ class VolumeAdapter( for (key in it) { if (volume.stream == key) { holder.binding.switchButton.isChecked = true - holder.binding.seekBar.isEnabled = false + holder.binding.slider.isEnabled = false } } } @@ -128,7 +119,7 @@ class VolumeAdapter( private fun handleRingerMode(holder: ViewHolder, volume: Volume) { if (volume.stream == AudioManager.STREAM_NOTIFICATION) { - holder.binding.seekBar.isEnabled = + holder.binding.slider.isEnabled = mService?.getMode() == 2 && mService?.getLocks()?.containsKey(AudioManager.STREAM_NOTIFICATION) == false } @@ -139,7 +130,7 @@ class VolumeAdapter( it.addLock(volume.stream, volume.value) adjustService() adjustNotification() - holder.binding.seekBar.isEnabled = false + holder.binding.slider.isEnabled = false } } @@ -148,7 +139,7 @@ class VolumeAdapter( it.removeLock(volume.stream) adjustService() adjustNotification() - holder.binding.seekBar.isEnabled = true + holder.binding.slider.isEnabled = true } } diff --git a/app/src/main/java/com/klee/volumelockr/ui/VolumeLockrApplication.kt b/app/src/main/java/com/klee/volumelockr/ui/VolumeLockrApplication.kt new file mode 100644 index 0000000..44d16ab --- /dev/null +++ b/app/src/main/java/com/klee/volumelockr/ui/VolumeLockrApplication.kt @@ -0,0 +1,11 @@ +package com.klee.volumelockr.ui + +import android.app.Application +import com.google.android.material.color.DynamicColors + +class VolumeLockrApplication: Application() { + override fun onCreate() { + super.onCreate() + DynamicColors.applyToActivitiesIfAvailable(this) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/preference_switch.xml b/app/src/main/res/layout/preference_switch.xml new file mode 100644 index 0000000..99df707 --- /dev/null +++ b/app/src/main/res/layout/preference_switch.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/volume_card.xml b/app/src/main/res/layout/volume_card.xml index 5494e1d..04738fc 100644 --- a/app/src/main/res/layout/volume_card.xml +++ b/app/src/main/res/layout/volume_card.xml @@ -1,12 +1,11 @@ - - - - - + \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml deleted file mode 100644 index b46415f..0000000 --- a/app/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index a0077b9..efd56ba 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,16 +1,14 @@ - - \ No newline at end of file + + + + + diff --git a/build.gradle b/build.gradle index c456e8f..43d418d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.5.20" + ext.kotlin_version = '1.8.0' repositories { google() mavenCentral() @@ -9,7 +9,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:7.0.4' + classpath 'com.android.tools.build:gradle:8.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:8.9.0" diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png index 1d1d271..2b33c2d 100644 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png index b053184..0149537 100644 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png and b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png differ diff --git a/gradle.properties b/gradle.properties index 2521752..dced600 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,4 +16,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a2e01c0..8307a0f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f581709a9c35e9cb92e16f585d2c4bc99b2b1a5f85d2badbd3dc6bff59e1e6dd -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/screenshot.png b/screenshot.png deleted file mode 100644 index d3ad445..0000000 Binary files a/screenshot.png and /dev/null differ diff --git a/screenshot_night.png b/screenshot_night.png deleted file mode 100644 index 2c8a254..0000000 Binary files a/screenshot_night.png and /dev/null differ