Handle timer notifications

This commit is contained in:
Paul Akhamiogu
2021-09-02 20:27:07 +01:00
parent 9b421b3676
commit 9df105ae8d
11 changed files with 97 additions and 23 deletions

View File

@ -27,7 +27,7 @@ import org.greenrobot.eventbus.ThreadMode
class App : Application(), LifecycleObserver { class App : Application(), LifecycleObserver {
private var timers = mutableMapOf<Long, CountDownTimer>() private var countDownTimers = mutableMapOf<Long, CountDownTimer>()
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -62,7 +62,9 @@ class App : Application(), LifecycleObserver {
timerHelper.getTimers { timers -> timerHelper.getTimers { timers ->
val runningTimers = timers.filter { it.state is TimerState.Running } val runningTimers = timers.filter { it.state is TimerState.Running }
runningTimers.forEach { timer -> runningTimers.forEach { timer ->
EventBus.getDefault().post(TimerEvent.Start(timer.id!!, (timer.state as TimerState.Running).tick)) if (countDownTimers[timer.id] == null) {
EventBus.getDefault().post(TimerEvent.Start(timer.id!!, (timer.state as TimerState.Running).tick))
}
} }
} }
} }
@ -71,7 +73,7 @@ class App : Application(), LifecycleObserver {
fun onMessageEvent(event: TimerEvent.Reset) { fun onMessageEvent(event: TimerEvent.Reset) {
Log.w(TAG, "onMessageEvent: $event") Log.w(TAG, "onMessageEvent: $event")
updateTimerState(event.timerId, TimerState.Idle) updateTimerState(event.timerId, TimerState.Idle)
timers[event.timerId]?.cancel() countDownTimers[event.timerId]?.cancel()
} }
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
@ -88,7 +90,7 @@ class App : Application(), LifecycleObserver {
EventBus.getDefault().post(TimerStopService) EventBus.getDefault().post(TimerStopService)
} }
}.start() }.start()
timers[event.timerId] = countDownTimer countDownTimers[event.timerId] = countDownTimer
} }
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
@ -108,7 +110,7 @@ class App : Application(), LifecycleObserver {
Log.w(TAG, "onMessageEvent: $event") Log.w(TAG, "onMessageEvent: $event")
timerHelper.getTimer(event.timerId) { timer -> timerHelper.getTimer(event.timerId) { timer ->
updateTimerState(event.timerId, TimerState.Paused(event.duration, (timer.state as TimerState.Running).tick)) updateTimerState(event.timerId, TimerState.Paused(event.duration, (timer.state as TimerState.Running).tick))
timers[event.timerId]?.cancel() countDownTimers[event.timerId]?.cancel()
} }
} }

View File

@ -3,6 +3,7 @@ package com.simplemobiletools.clock.activities
import android.content.Intent import android.content.Intent
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.WindowManager import android.view.WindowManager
@ -19,9 +20,11 @@ import com.simplemobiletools.commons.helpers.LICENSE_RTL
import com.simplemobiletools.commons.helpers.LICENSE_STETHO import com.simplemobiletools.commons.helpers.LICENSE_STETHO
import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.models.FAQItem import com.simplemobiletools.commons.models.FAQItem
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.main_tabs_holder
import kotlinx.android.synthetic.main.activity_main.view_pager
class MainActivity : SimpleActivity() { class MainActivity : SimpleActivity() {
private val TAG = "MainActivity"
private var storedTextColor = 0 private var storedTextColor = 0
private var storedBackgroundColor = 0 private var storedBackgroundColor = 0
private var storedPrimaryColor = 0 private var storedPrimaryColor = 0
@ -29,8 +32,8 @@ class MainActivity : SimpleActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
intent.extras?.printAllItems("onCreate")
appLaunched(BuildConfig.APPLICATION_ID) appLaunched(BuildConfig.APPLICATION_ID)
storeStateVariables() storeStateVariables()
initFragments() initFragments()
@ -100,9 +103,17 @@ class MainActivity : SimpleActivity() {
} }
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
intent.extras?.printAllItems("onNewIntent")
if (intent.extras?.containsKey(OPEN_TAB) == true) { if (intent.extras?.containsKey(OPEN_TAB) == true) {
view_pager.setCurrentItem(intent.getIntExtra(OPEN_TAB, TAB_CLOCK), false) val tabToOpen = intent.getIntExtra(OPEN_TAB, TAB_CLOCK)
view_pager.setCurrentItem(tabToOpen, false)
if (tabToOpen == TAB_TIMER) {
val timerId = intent.getLongExtra(TIMER_ID, INVALID_TIMER_ID)
Log.e(TAG, "onNewIntent: TIMER ID: $timerId")
(view_pager.adapter as ViewPagerAdapter).updateTimerPosition(timerId)
}
} }
super.onNewIntent(intent)
} }
private fun storeStateVariables() { private fun storeStateVariables() {
@ -136,7 +147,8 @@ class MainActivity : SimpleActivity() {
private fun getViewPagerAdapter() = view_pager.adapter as? ViewPagerAdapter private fun getViewPagerAdapter() = view_pager.adapter as? ViewPagerAdapter
private fun initFragments() { private fun initFragments() {
view_pager.adapter = ViewPagerAdapter(supportFragmentManager) val viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
view_pager.adapter = viewPagerAdapter
view_pager.onPageChangeListener { view_pager.onPageChangeListener {
main_tabs_holder.getTabAt(it)?.select() main_tabs_holder.getTabAt(it)?.select()
invalidateOptionsMenu() invalidateOptionsMenu()
@ -144,6 +156,12 @@ class MainActivity : SimpleActivity() {
val tabToOpen = intent.getIntExtra(OPEN_TAB, config.lastUsedViewPagerPage) val tabToOpen = intent.getIntExtra(OPEN_TAB, config.lastUsedViewPagerPage)
intent.removeExtra(OPEN_TAB) intent.removeExtra(OPEN_TAB)
if (tabToOpen == TAB_TIMER) {
Log.e(TAG, "initFragments: TIMER")
val timerId = intent.getLongExtra(TIMER_ID, INVALID_TIMER_ID)
Log.e(TAG, "initFragments: TIMER ID: $timerId")
viewPagerAdapter.updateTimerPosition(timerId)
}
view_pager.currentItem = tabToOpen view_pager.currentItem = tabToOpen
view_pager.offscreenPageLimit = TABS_COUNT - 1 view_pager.offscreenPageLimit = TABS_COUNT - 1
main_tabs_holder.onTabSelectionChanged( main_tabs_holder.onTabSelectionChanged(
@ -195,3 +213,9 @@ class MainActivity : SimpleActivity() {
startAboutActivity(R.string.app_name, licenses, BuildConfig.VERSION_NAME, faqItems, true) startAboutActivity(R.string.app_name, licenses, BuildConfig.VERSION_NAME, faqItems, true)
} }
} }
fun Bundle.printAllItems(where:String) {
for (key in keySet()) {
Log.e(where, "Item: key: $key - value: ${get(key)}")
}
}

View File

@ -1,9 +1,7 @@
package com.simplemobiletools.clock.activities package com.simplemobiletools.clock.activities
import android.content.Intent import android.content.Intent
import com.simplemobiletools.clock.helpers.OPEN_TAB import com.simplemobiletools.clock.helpers.*
import com.simplemobiletools.clock.helpers.TAB_ALARM
import com.simplemobiletools.clock.helpers.TAB_CLOCK
import com.simplemobiletools.commons.activities.BaseSplashActivity import com.simplemobiletools.commons.activities.BaseSplashActivity
class SplashActivity : BaseSplashActivity() { class SplashActivity : BaseSplashActivity() {
@ -18,6 +16,7 @@ class SplashActivity : BaseSplashActivity() {
intent.extras?.containsKey(OPEN_TAB) == true -> { intent.extras?.containsKey(OPEN_TAB) == true -> {
Intent(this, MainActivity::class.java).apply { Intent(this, MainActivity::class.java).apply {
putExtra(OPEN_TAB, intent.getIntExtra(OPEN_TAB, TAB_CLOCK)) putExtra(OPEN_TAB, intent.getIntExtra(OPEN_TAB, TAB_CLOCK))
putExtra(TIMER_ID, intent.getLongExtra(TIMER_ID, INVALID_TIMER_ID))
startActivity(this) startActivity(this)
} }
} }

View File

@ -134,7 +134,7 @@ class TimerAdapter(
fun updateAlarmSound(timer: Timer, alarmSound: AlarmSound) { fun updateAlarmSound(timer: Timer, alarmSound: AlarmSound) {
Log.w(TAG, "updateAlarmSound: $timer") Log.w(TAG, "updateAlarmSound: $timer")
updateTimer(timer.copy(soundTitle = alarmSound.title, soundUri = alarmSound.uri)) updateTimer(timer.copy(soundTitle = alarmSound.title, soundUri = alarmSound.uri, channelId = null))
} }
private fun updateTimer(timer: Timer, refresh: Boolean = true) { private fun updateTimer(timer: Timer, refresh: Boolean = true) {

View File

@ -1,5 +1,6 @@
package com.simplemobiletools.clock.adapters package com.simplemobiletools.clock.adapters
import android.util.Log
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
@ -53,4 +54,11 @@ class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
fun updateTimerTabAlarmSound(alarmSound: AlarmSound) { fun updateTimerTabAlarmSound(alarmSound: AlarmSound) {
(fragments[TAB_TIMER] as? TimerFragment)?.updateAlarmSound(alarmSound) (fragments[TAB_TIMER] as? TimerFragment)?.updateAlarmSound(alarmSound)
} }
private val TAG = "ViewPagerAdapter"
fun updateTimerPosition(timerId: Long) {
Log.e(TAG, "updateTimerPosition: $timerId")
(fragments[TAB_TIMER] as? TimerFragment)?.updatePosition(timerId)
}
} }

View File

@ -13,6 +13,7 @@ import android.net.Uri
import android.os.PowerManager import android.os.PowerManager
import android.text.SpannableString import android.text.SpannableString
import android.text.style.RelativeSizeSpan import android.text.style.RelativeSizeSpan
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.core.app.AlarmManagerCompat import androidx.core.app.AlarmManagerCompat
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
@ -20,6 +21,7 @@ import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.activities.ReminderActivity import com.simplemobiletools.clock.activities.ReminderActivity
import com.simplemobiletools.clock.activities.SnoozeReminderActivity import com.simplemobiletools.clock.activities.SnoozeReminderActivity
import com.simplemobiletools.clock.activities.SplashActivity import com.simplemobiletools.clock.activities.SplashActivity
import com.simplemobiletools.clock.activities.printAllItems
import com.simplemobiletools.clock.databases.AppDatabase import com.simplemobiletools.clock.databases.AppDatabase
import com.simplemobiletools.clock.helpers.* import com.simplemobiletools.clock.helpers.*
import com.simplemobiletools.clock.interfaces.TimerDao import com.simplemobiletools.clock.interfaces.TimerDao
@ -144,6 +146,7 @@ fun Context.getOpenTimerTabIntent(timerId: Long): PendingIntent {
val intent = getLaunchIntent() ?: Intent(this, SplashActivity::class.java) val intent = getLaunchIntent() ?: Intent(this, SplashActivity::class.java)
intent.putExtra(OPEN_TAB, TAB_TIMER) intent.putExtra(OPEN_TAB, TAB_TIMER)
intent.putExtra(TIMER_ID, timerId) intent.putExtra(TIMER_ID, timerId)
intent.extras?.printAllItems("getOpenTimerTabIntent")
return PendingIntent.getActivity(this, TIMER_NOTIF_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) return PendingIntent.getActivity(this, TIMER_NOTIF_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
} }
@ -260,7 +263,7 @@ fun Context.showAlarmNotification(alarm: Alarm) {
scheduleNextAlarm(alarm, false) scheduleNextAlarm(alarm, false)
} }
} }
private const val TAG = "ALARMMMM"
@SuppressLint("NewApi") @SuppressLint("NewApi")
fun Context.getTimerNotification(timer: Timer, pendingIntent: PendingIntent, addDeleteIntent: Boolean): Notification { fun Context.getTimerNotification(timer: Timer, pendingIntent: PendingIntent, addDeleteIntent: Boolean): Notification {
var soundUri = timer.soundUri var soundUri = timer.soundUri
@ -270,9 +273,12 @@ fun Context.getTimerNotification(timer: Timer, pendingIntent: PendingIntent, add
grantReadUriPermission(soundUri) grantReadUriPermission(soundUri)
} }
Log.w(TAG, "getTimerNotification: timerSOUNDURI=${timer.soundUri}")
Log.w(TAG, "getTimerNotification: soundUri=${soundUri}")
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelId = config.timerChannelId ?: "simple_timer_channel_${soundUri}_${System.currentTimeMillis()}" val channelId = timer.channelId ?: "simple_timer_channel_${soundUri}_${System.currentTimeMillis()}"
config.timerChannelId = channelId timerHelper.insertOrUpdateTimer(timer.copy(channelId = channelId))
if (isOreoPlus()) { if (isOreoPlus()) {
try { try {

View File

@ -27,9 +27,10 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
class TimerFragment : Fragment() { class TimerFragment : Fragment() {
private val INVALID_POSITION = -1
private lateinit var view: ViewGroup private lateinit var view: ViewGroup
private lateinit var timerAdapter: TimerAdapter private lateinit var timerAdapter: TimerAdapter
private var timerPositionToScrollTo = INVALID_POSITION
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -116,8 +117,13 @@ class TimerFragment : Fragment() {
activity?.timerHelper?.getTimers { timers -> activity?.timerHelper?.getTimers { timers ->
Log.d(TAG, "refreshTimers: $timers") Log.d(TAG, "refreshTimers: $timers")
timerAdapter.submitList(timers) { timerAdapter.submitList(timers) {
if (scrollToLatest) { Log.e(TAG, "submitted list: timerPositionToScrollTo=$timerPositionToScrollTo")
view.timer_view_pager.currentItem = 0 if (timerPositionToScrollTo != INVALID_POSITION && timerAdapter.itemCount > timerPositionToScrollTo) {
Log.e(TAG, "scrolling to position=$timerPositionToScrollTo")
view.timer_view_pager.setCurrentItem(timerPositionToScrollTo, false)
timerPositionToScrollTo = INVALID_POSITION
} else if (scrollToLatest) {
view.timer_view_pager.setCurrentItem(0, false)
} }
updateViews(timer_view_pager.currentItem) updateViews(timer_view_pager.currentItem)
} }
@ -162,6 +168,25 @@ class TimerFragment : Fragment() {
} }
} }
fun updatePosition(timerId: Long) {
Log.e(TAG, "updatePosition TIMER: $timerId")
activity?.timerHelper?.getTimers { timers ->
val position = timers.indexOfFirst { it.id == timerId }
Log.e(TAG, "updatePosition POSITION: $position")
if (position != INVALID_POSITION) {
activity?.runOnUiThread {
if (timerAdapter.itemCount > position) {
Log.e(TAG, "updatePosition now: $position")
view.timer_view_pager.setCurrentItem(position, false)
} else {
Log.e(TAG, "updatePosition later: $position")
timerPositionToScrollTo = position
}
}
}
}
}
companion object { companion object {
private const val TAG = "TimerFragment" private const val TAG = "TimerFragment"
} }

View File

@ -45,7 +45,8 @@ const val TAB_CLOCK = 0
const val TAB_ALARM = 1 const val TAB_ALARM = 1
const val TAB_STOPWATCH = 2 const val TAB_STOPWATCH = 2
const val TAB_TIMER = 3 const val TAB_TIMER = 3
const val TIMER_ID = "timer_position" const val TIMER_ID = "timer_id"
const val INVALID_TIMER_ID = -1L
// stopwatch sorting // stopwatch sorting
const val SORT_BY_LAP = 1 const val SORT_BY_LAP = 1

View File

@ -45,7 +45,8 @@ class TimerHelper(val context: Context) {
timerDao.insertOrUpdateTimer( timerDao.insertOrUpdateTimer(
Timer( Timer(
id = null, id = null,
seconds = DEFAULT_TIME, // seconds = DEFAULT_TIME,
seconds = 5,
TimerState.Idle, TimerState.Idle,
false, false,
context.getDefaultAlarmSound(RingtoneManager.TYPE_ALARM).uri, context.getDefaultAlarmSound(RingtoneManager.TYPE_ALARM).uri,

View File

@ -13,4 +13,5 @@ data class Timer(
val soundTitle: String, val soundTitle: String,
val label: String, val label: String,
val createdAt: Long, val createdAt: Long,
val channelId: String? = null,
) )

View File

@ -9,12 +9,14 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.simplemobiletools.clock.R import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.extensions.getFormattedDuration import com.simplemobiletools.clock.extensions.getFormattedDuration
import com.simplemobiletools.clock.extensions.getOpenTimerTabIntent import com.simplemobiletools.clock.extensions.getOpenTimerTabIntent
import com.simplemobiletools.clock.extensions.timerHelper import com.simplemobiletools.clock.extensions.timerHelper
import com.simplemobiletools.clock.helpers.INVALID_TIMER_ID
import com.simplemobiletools.clock.helpers.TIMER_RUNNING_NOTIF_ID import com.simplemobiletools.clock.helpers.TIMER_RUNNING_NOTIF_ID
import com.simplemobiletools.clock.models.TimerEvent import com.simplemobiletools.clock.models.TimerEvent
import com.simplemobiletools.clock.models.TimerState import com.simplemobiletools.clock.models.TimerState
@ -39,7 +41,7 @@ class TimerService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId) super.onStartCommand(intent, flags, startId)
updateNotification() updateNotification()
startForeground(TIMER_RUNNING_NOTIF_ID, notification(getString(R.string.app_name), getString(R.string.timer_notification_msg), -1)) startForeground(TIMER_RUNNING_NOTIF_ID, notification(getString(R.string.app_name), getString(R.string.timer_notification_msg), INVALID_TIMER_ID))
return START_NOT_STICKY return START_NOT_STICKY
} }
@ -111,13 +113,18 @@ class TimerService : Service() {
.setAutoCancel(true) .setAutoCancel(true)
.setChannelId(channelId) .setChannelId(channelId)
if (firstRunningTimerId != -1L) { if (firstRunningTimerId != INVALID_TIMER_ID) {
Log.e(TAG, "notification: Setting content intent for $firstRunningTimerId" )
builder.setContentIntent(this.getOpenTimerTabIntent(firstRunningTimerId)) builder.setContentIntent(this.getOpenTimerTabIntent(firstRunningTimerId))
} }
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
return builder.build() return builder.build()
} }
companion object {
private const val TAG = "TimerService"
}
} }
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)