Make timer alarm have a stop button
This commit is contained in:
parent
88d751f13b
commit
3cb6e8757b
|
@ -149,6 +149,8 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||||
implementation 'com.google.android.material:material:1.4.+'
|
implementation 'com.google.android.material:material:1.4.+'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
|
implementation 'androidx.databinding:databinding-runtime:7.1.2'
|
||||||
def work_version = "2.7.1"
|
def work_version = "2.7.1"
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime:$work_version"
|
implementation "androidx.work:work-runtime:$work_version"
|
||||||
|
|
|
@ -21,17 +21,12 @@
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity
|
<activity
|
||||||
android:name=".Fullscreen"
|
android:name=".TimerDone"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
android:exported="false">
|
||||||
android:exported="false"
|
<meta-data
|
||||||
android:label="@string/title_activity_fullscreen"
|
android:name="android.app.lib_name"
|
||||||
android:theme="@style/AppTheme.Fullscreen" />
|
android:value="" />
|
||||||
<activity
|
</activity>
|
||||||
android:name=".FullscreenActivity"
|
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
|
||||||
android:exported="false"
|
|
||||||
android:label="@string/title_activity_fullscreen"
|
|
||||||
android:theme="@style/AppTheme.Fullscreen" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||||
|
@ -51,14 +46,14 @@
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".StopTimer"
|
android:name=".StopTimer"
|
||||||
android:exported="true"
|
android:exported="false"
|
||||||
android:process=":remote" />
|
android:process=":remote" />
|
||||||
<service
|
<service
|
||||||
android:name=".AlarmService"
|
android:name=".AlarmService"
|
||||||
android:exported="true" />
|
android:exported="false" />
|
||||||
<service
|
<service
|
||||||
android:name=".TimerService"
|
android:name=".TimerService"
|
||||||
android:exported="true" />
|
android:exported="false" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -1,185 +0,0 @@
|
||||||
package com.massive
|
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.WindowInsets
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
|
||||||
import com.massive.databinding.ActivityFullscreenBinding
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An example full-screen activity that shows and hides the system UI (i.e.
|
|
||||||
* status bar and navigation/system bar) with user interaction.
|
|
||||||
*/
|
|
||||||
class Fullscreen : AppCompatActivity() {
|
|
||||||
|
|
||||||
private lateinit var binding: ActivityFullscreenBinding
|
|
||||||
private lateinit var fullscreenContent: TextView
|
|
||||||
private lateinit var fullscreenContentControls: LinearLayout
|
|
||||||
private val hideHandler = Handler(Looper.myLooper()!!)
|
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
private val hidePart2Runnable = Runnable {
|
|
||||||
// Delayed removal of status and navigation bar
|
|
||||||
if (Build.VERSION.SDK_INT >= 30) {
|
|
||||||
fullscreenContent.windowInsetsController?.hide(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars())
|
|
||||||
} else {
|
|
||||||
// Note that some of these constants are new as of API 16 (Jelly Bean)
|
|
||||||
// and API 19 (KitKat). It is safe to use them, as they are inlined
|
|
||||||
// at compile-time and do nothing on earlier devices.
|
|
||||||
fullscreenContent.systemUiVisibility =
|
|
||||||
View.SYSTEM_UI_FLAG_LOW_PROFILE or
|
|
||||||
View.SYSTEM_UI_FLAG_FULLSCREEN or
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
|
||||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
|
||||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private val showPart2Runnable = Runnable {
|
|
||||||
// Delayed display of UI elements
|
|
||||||
supportActionBar?.show()
|
|
||||||
fullscreenContentControls.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
private var isFullscreen: Boolean = false
|
|
||||||
|
|
||||||
private val hideRunnable = Runnable { hide() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Touch listener to use for in-layout UI controls to delay hiding the
|
|
||||||
* system UI. This is to prevent the jarring behavior of controls going away
|
|
||||||
* while interacting with activity UI.
|
|
||||||
*/
|
|
||||||
private val delayHideTouchListener = View.OnTouchListener { view, motionEvent ->
|
|
||||||
when (motionEvent.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> if (AUTO_HIDE) {
|
|
||||||
delayedHide(AUTO_HIDE_DELAY_MILLIS)
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_UP -> view.performClick()
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun stop() {
|
|
||||||
Log.d("Fullscreen", "Stopping...")
|
|
||||||
applicationContext.stopService(Intent(applicationContext, TimerService::class.java))
|
|
||||||
applicationContext.stopService(Intent(applicationContext, AlarmService::class.java))
|
|
||||||
val intent = Intent(applicationContext, MainActivity::class.java)
|
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
applicationContext.startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
binding = ActivityFullscreenBinding.inflate(layoutInflater)
|
|
||||||
setContentView(binding.root)
|
|
||||||
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
||||||
|
|
||||||
isFullscreen = true
|
|
||||||
|
|
||||||
// Set up the user interaction to manually show or hide the system UI.
|
|
||||||
fullscreenContent = binding.fullscreenContent
|
|
||||||
fullscreenContent.setOnClickListener { toggle() }
|
|
||||||
|
|
||||||
fullscreenContentControls = binding.fullscreenContentControls
|
|
||||||
|
|
||||||
// Upon interacting with UI controls, delay any scheduled hide()
|
|
||||||
// operations to prevent the jarring behavior of controls going away
|
|
||||||
// while interacting with the UI.
|
|
||||||
binding.dummyButton.setOnTouchListener(delayHideTouchListener)
|
|
||||||
|
|
||||||
binding.dummyButton.setOnClickListener {
|
|
||||||
stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.fullscreenContent.setOnClickListener {
|
|
||||||
stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPostCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onPostCreate(savedInstanceState)
|
|
||||||
|
|
||||||
// Trigger the initial hide() shortly after the activity has been
|
|
||||||
// created, to briefly hint to the user that UI controls
|
|
||||||
// are available.
|
|
||||||
delayedHide(100)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggle() {
|
|
||||||
if (isFullscreen) {
|
|
||||||
hide()
|
|
||||||
} else {
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hide() {
|
|
||||||
// Hide UI first
|
|
||||||
supportActionBar?.hide()
|
|
||||||
fullscreenContentControls.visibility = View.GONE
|
|
||||||
isFullscreen = false
|
|
||||||
|
|
||||||
// Schedule a runnable to remove the status and navigation bar after a delay
|
|
||||||
hideHandler.removeCallbacks(showPart2Runnable)
|
|
||||||
hideHandler.postDelayed(hidePart2Runnable, UI_ANIMATION_DELAY.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun show() {
|
|
||||||
// Show the system bar
|
|
||||||
if (Build.VERSION.SDK_INT >= 30) {
|
|
||||||
fullscreenContent.windowInsetsController?.show(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars())
|
|
||||||
} else {
|
|
||||||
fullscreenContent.systemUiVisibility =
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
||||||
}
|
|
||||||
isFullscreen = true
|
|
||||||
|
|
||||||
// Schedule a runnable to display UI elements after a delay
|
|
||||||
hideHandler.removeCallbacks(hidePart2Runnable)
|
|
||||||
hideHandler.postDelayed(showPart2Runnable, UI_ANIMATION_DELAY.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules a call to hide() in [delayMillis], canceling any
|
|
||||||
* previously scheduled calls.
|
|
||||||
*/
|
|
||||||
private fun delayedHide(delayMillis: Int) {
|
|
||||||
hideHandler.removeCallbacks(hideRunnable)
|
|
||||||
hideHandler.postDelayed(hideRunnable, delayMillis.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Whether or not the system UI should be auto-hidden after
|
|
||||||
* [AUTO_HIDE_DELAY_MILLIS] milliseconds.
|
|
||||||
*/
|
|
||||||
private const val AUTO_HIDE = true
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If [AUTO_HIDE] is set, the number of milliseconds to wait after
|
|
||||||
* user interaction before hiding the system UI.
|
|
||||||
*/
|
|
||||||
private const val AUTO_HIDE_DELAY_MILLIS = 3000
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Some older devices needs a small delay between UI widget updates
|
|
||||||
* and a change of the status and navigation bar.
|
|
||||||
*/
|
|
||||||
private const val UI_ANIMATION_DELAY = 300
|
|
||||||
}
|
|
||||||
}
|
|
23
android/app/src/main/java/com/massive/TimerDone.kt
Normal file
23
android/app/src/main/java/com/massive/TimerDone.kt
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package com.massive
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
class TimerDone : AppCompatActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_timer_done)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop(view: View) {
|
||||||
|
Log.d("TimerDone", "Stopping...")
|
||||||
|
applicationContext.stopService(Intent(applicationContext, TimerService::class.java))
|
||||||
|
applicationContext.stopService(Intent(applicationContext, AlarmService::class.java))
|
||||||
|
val intent = Intent(applicationContext, MainActivity::class.java)
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
applicationContext.startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
|
@ -73,7 +73,7 @@ class TimerService : Service() {
|
||||||
finishIntent,
|
finishIntent,
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
val fullIntent = Intent(applicationContext, Fullscreen::class.java)
|
val fullIntent = Intent(applicationContext, TimerDone::class.java)
|
||||||
val fullPending =
|
val fullPending =
|
||||||
PendingIntent.getActivity(
|
PendingIntent.getActivity(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/fullscreenBackgroundColor"
|
|
||||||
android:theme="@style/ThemeOverlay.Massive.FullscreenContainer"
|
|
||||||
tools:context=".Fullscreen">
|
|
||||||
|
|
||||||
<!-- The primary full-screen view. This can be replaced with whatever view
|
|
||||||
is needed to present your content, e.g. VideoView, SurfaceView,
|
|
||||||
TextureView, etc. -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/fullscreen_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center"
|
|
||||||
android:keepScreenOn="true"
|
|
||||||
android:text="@string/rest_timer_up"
|
|
||||||
android:textColor="?attr/fullscreenTextColor"
|
|
||||||
android:textSize="50sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<!-- This FrameLayout insets its children based on system windows using
|
|
||||||
android:fitsSystemWindows. -->
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:fitsSystemWindows="true">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/fullscreen_content_controls"
|
|
||||||
style="@style/Widget.AppTheme.ButtonBar.Fullscreen"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|center_horizontal"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
tools:ignore="UselessParent">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/dummy_button"
|
|
||||||
style="?android:attr/buttonBarButtonStyle"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/stop" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
30
android/app/src/main/res/layout/activity_timer_done.xml
Normal file
30
android/app/src/main/res/layout/activity_timer_done.xml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".TimerDone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Timer up"
|
||||||
|
android:textSize="28sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Stop"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textView"
|
||||||
|
android:onClick="stop" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue
Block a user