Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.idea
.gradle
local.properties
build/
.kotlin/
15 changes: 7 additions & 8 deletions app/src/main/java/com/klee/volumelockr/service/VolumeService.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.klee.volumelockr.service

import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
Expand Down Expand Up @@ -90,6 +89,11 @@ class VolumeService : Service() {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
tryShowNotification()

if (mVolumeLock.isEmpty()) {
stopForeground(Service.STOP_FOREGROUND_REMOVE)
stopSelf()
}
}
}

Expand Down Expand Up @@ -262,10 +266,6 @@ class VolumeService : Service() {
@RequiresApi(Build.VERSION_CODES.O)
@Synchronized
fun tryShowNotification() {
if (mVolumeLock.isEmpty()) {
return
}

createNotificationChannel()
val notification = Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
.setContentTitle(NOTIFICATION_TITLE)
Expand All @@ -277,15 +277,14 @@ class VolumeService : Service() {
startForeground(NOTIFICATION_ID, notification)
}

@SuppressLint("WrongConstant")
@RequiresApi(Build.VERSION_CODES.N)
@Synchronized
fun tryHideNotification() {
if (mVolumeLock.isNotEmpty()) {
return
}

stopForeground(NOTIFICATION_ID)
stopForeground(Service.STOP_FOREGROUND_REMOVE)
}

private fun createNotificationContentIntent(): PendingIntent {
Expand Down Expand Up @@ -324,4 +323,4 @@ class VolumeService : Service() {
unregisterObservers()
stopLocking()
}
}
}
57 changes: 57 additions & 0 deletions app/src/main/java/com/klee/volumelockr/ui/AboutFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.klee.volumelockr.ui

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.klee.volumelockr.R
import com.mikepenz.aboutlibraries.LibsBuilder

class AboutFragment : Fragment() {

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_about, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

if (savedInstanceState == null) {
val libsFragment = LibsBuilder()
.supportFragment()

childFragmentManager.beginTransaction()
.add(R.id.about_libs_container, libsFragment)
.commitNow()
}

view.post {
val recyclerView = findRecyclerView(view)
recyclerView?.let { rv ->
val spanCount = if (resources.configuration.screenWidthDp >= 600) 2 else 1
if (spanCount > 1) {
rv.layoutManager = GridLayoutManager(requireContext(), spanCount)
}
}
}
}

private fun findRecyclerView(view: View): RecyclerView? {
if (view is RecyclerView) return view
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val child = view.getChildAt(i)
val rv = findRecyclerView(child)
if (rv != null) return rv
}
}
return null
}
}
73 changes: 47 additions & 26 deletions app/src/main/java/com/klee/volumelockr/ui/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package com.klee.volumelockr.ui

import android.app.AlertDialog
import android.app.Dialog
import android.app.NotificationManager
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.DialogFragment
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.navigation.NavigationBarView
import com.klee.volumelockr.R
import com.klee.volumelockr.databinding.ActivityMainBinding

Expand All @@ -20,10 +20,12 @@ class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
handleEdgeToEdgeInsets()
setupNavigation()
setupWindowInsets()
}

override fun onResume() {
Expand All @@ -34,6 +36,20 @@ class MainActivity : AppCompatActivity() {
}
}

private fun setupNavigation() {
setSupportActionBar(binding.toolbar)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.fragment_container_view) as NavHostFragment
val navController = navHostFragment.navController
val appBarConfiguration = AppBarConfiguration(
setOf(R.id.volumeSliderFragment, R.id.settingsFragment, R.id.about_libraries)
)
binding.toolbar.setupWithNavController(navController, appBarConfiguration)

val navView: NavigationBarView? = binding.bottomNavigation ?: binding.navigationRail
navView?.setupWithNavController(navController)
}

@RequiresApi(Build.VERSION_CODES.M)
private fun checkDoNotDisturbPermission() {
val notificationManager =
Expand All @@ -44,32 +60,37 @@ class MainActivity : AppCompatActivity() {
}
}

class PolicyAccessDialog : DialogFragment() {
companion object {
const val TAG = "PolicyAccessDialog"
}

@RequiresApi(Build.VERSION_CODES.M)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
AlertDialog.Builder(requireContext())
.setMessage(getString(R.string.dialog_policy_access_title))
.setCancelable(false)
.setPositiveButton(getString(R.string.dialog_allow)) { _, _ ->
startActivity(Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS))
}
.create()
}

private fun handleEdgeToEdgeInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, windowInsets ->
private fun setupWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.appBarLayout) { v, windowInsets ->
val bars = windowInsets.getInsets(
WindowInsetsCompat.Type.systemBars()
or WindowInsetsCompat.Type.displayCutout()
)
v.setPadding(bars.left, bars.top, bars.right, 0)
WindowInsetsCompat.CONSUMED
}

v.setPadding(bars.left, bars.top, bars.right, bars.bottom)
binding.bottomNavigation?.let { view ->
ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
val bars = windowInsets.getInsets(
WindowInsetsCompat.Type.systemBars()
or WindowInsetsCompat.Type.displayCutout()
)
v.setPadding(bars.left, 0, bars.right, bars.bottom)
WindowInsetsCompat.CONSUMED
}
}

WindowInsetsCompat.CONSUMED
binding.navigationRail?.let { view ->
ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
val bars = windowInsets.getInsets(
WindowInsetsCompat.Type.systemBars()
or WindowInsetsCompat.Type.displayCutout()
)
// Rail needs top and bottom padding usually, and left padding
v.setPadding(bars.left, bars.top, 0, bars.bottom)
WindowInsetsCompat.CONSUMED
}
}
}
}
27 changes: 27 additions & 0 deletions app/src/main/java/com/klee/volumelockr/ui/PolicyAccessDialog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.klee.volumelockr.ui

import android.app.AlertDialog
import android.app.Dialog
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.fragment.app.DialogFragment
import com.klee.volumelockr.R

class PolicyAccessDialog : DialogFragment() {
companion object {
const val TAG = "PolicyAccessDialog"
}

@RequiresApi(Build.VERSION_CODES.M)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
AlertDialog.Builder(requireContext())
.setMessage(getString(R.string.dialog_policy_access_title))
.setCancelable(false)
.setPositiveButton(getString(R.string.dialog_allow)) { _, _ ->
startActivity(Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS))
}
.create()
}
27 changes: 0 additions & 27 deletions app/src/main/java/com/klee/volumelockr/ui/SettingsFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import android.text.InputType
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
Expand Down Expand Up @@ -62,31 +60,6 @@ class SettingsFragment : PreferenceFragmentCompat() {
passwordProtected.isEnabled = isPasswordSet()
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

val preferenceList = listView
val startPadding = preferenceList.paddingLeft
val topPadding = preferenceList.paddingTop
val endPadding = preferenceList.paddingRight
val bottomPadding = preferenceList.paddingBottom

ViewCompat.setOnApplyWindowInsetsListener(preferenceList) { v, windowInsets ->
val bars = windowInsets.getInsets(
WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
)

v.setPadding(
startPadding + bars.left,
topPadding + bars.top,
endPadding + bars.right,
bottomPadding + bars.bottom
)

WindowInsetsCompat.CONSUMED
}
}

private fun askForPassword() {
val editText = EditText(context)
editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
Expand Down
53 changes: 2 additions & 51 deletions app/src/main/java/com/klee/volumelockr/ui/VolumeSliderFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,10 @@ import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.klee.volumelockr.R
import com.klee.volumelockr.databinding.FragmentVolumeSliderBinding
import com.klee.volumelockr.service.VolumeService

Expand All @@ -36,16 +29,10 @@ class VolumeSliderFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
setHasOptionsMenu(true)
_binding = FragmentVolumeSliderBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
handleEdgeToEdgeInsets()
}

override fun onResume() {
super.onResume()
mService?.let {
Expand All @@ -67,49 +54,13 @@ class VolumeSliderFragment : Fragment() {
super.onDestroyView()
}

override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.options, menu)
super.onCreateOptionsMenu(menu, menuInflater)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.about -> findNavController().navigate(R.id.action_x_to_about_libs)
R.id.options -> findNavController().navigate(R.id.action_sliders_to_settings)
}
return true
}

private fun setupRecyclerView(service: VolumeService) {
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
val spanCount = if (resources.configuration.screenWidthDp >= 600) 2 else 1
binding.recyclerView.layoutManager = androidx.recyclerview.widget.GridLayoutManager(requireContext(), spanCount)
mAdapter = VolumeAdapter(service.getVolumes(), service, requireContext())
binding.recyclerView.adapter = mAdapter
}

private fun handleEdgeToEdgeInsets() {
val recyclerView = binding.recyclerView
val startPadding = recyclerView.paddingLeft
val topPadding = recyclerView.paddingTop
val endPadding = recyclerView.paddingRight
val bottomPadding = recyclerView.paddingBottom

ViewCompat.setOnApplyWindowInsetsListener(recyclerView) { v, insets ->
val bars = insets.getInsets(
WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
)

v.setPadding(
startPadding + bars.left,
topPadding + bars.top,
endPadding + bars.right,
bottomPadding + bars.bottom
)

WindowInsetsCompat.CONSUMED
}
}

private val connection = object : ServiceConnection {

override fun onServiceConnected(className: ComponentName?, service: IBinder?) {
Expand Down
Loading