Started playing around with alerts

This commit is contained in:
Sylvain Berfini 2023-08-28 15:57:14 +02:00
parent 294410bfd2
commit 39ad8347c7
10 changed files with 213 additions and 11 deletions

View file

@ -53,4 +53,7 @@ url=https://subscribe.linphone.org/api/
[lime]
lime_update_threshold=86400
[alerts]
alerts_enabled=1
## End of factory rc

View file

@ -26,6 +26,7 @@ import android.net.Uri
import android.os.Bundle
import android.provider.ContactsContract
import android.util.Patterns
import androidx.annotation.MainThread
import androidx.loader.app.LoaderManager
import androidx.loader.content.CursorLoader
import androidx.loader.content.Loader
@ -50,6 +51,7 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
)
}
@MainThread
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
val mimeType = ContactsContract.Data.MIMETYPE
val mimeSelection = "$mimeType = ? OR $mimeType = ? OR $mimeType = ? OR $mimeType = ?"
@ -72,6 +74,7 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
)
}
@MainThread
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor?) {
if (cursor == null) {
Log.e("[Contacts Loader] Cursor is null!")
@ -79,15 +82,14 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
}
Log.i("[Contacts Loader] Load finished, found ${cursor.count} entries in cursor")
val state = coreContext.core.globalState
if (state == GlobalState.Shutdown || state == GlobalState.Off) {
Log.w("[Contacts Loader] Core is being stopped or already destroyed, abort")
return
}
coreContext.postOnCoreThread { core ->
val friends = HashMap<String, Friend>()
val state = coreContext.core.globalState
if (state == GlobalState.Shutdown || state == GlobalState.Off) {
Log.w("[Contacts Loader] Core is being stopped or already destroyed, abort")
return@postOnCoreThread
}
val friends = HashMap<String, Friend>()
try {
// Cursor can be null now that we are on a different dispatcher according to Crashlytics
val friendsPhoneNumbers = arrayListOf<String>()
@ -315,6 +317,7 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
}
}
@MainThread
override fun onLoaderReset(loader: Loader<Cursor>) {
Log.i("[Contacts Loader] Loader reset")
}

View file

@ -45,6 +45,7 @@ import org.linphone.ui.voip.model.AudioDeviceModel
import org.linphone.ui.voip.viewmodel.CallsViewModel
import org.linphone.ui.voip.viewmodel.CurrentCallViewModel
import org.linphone.ui.voip.viewmodel.SharedCallViewModel
import org.linphone.utils.slideInToastFromTop
import org.linphone.utils.slideInToastFromTopForDuration
@UiThread
@ -132,6 +133,17 @@ class VoipActivity : AppCompatActivity() {
}
}
callsViewModel.showLowSignalEvent.observe(this) {
it.consume { show ->
if (show) {
showRedToast("Low Wi-Fi signal!", R.drawable.wifi_low)
} else {
hideRedToast()
showGreenToast("Wi-Fi signal no longer low", R.drawable.wifi_high)
}
}
}
sharedViewModel.toggleFullScreenEvent.observe(this) {
it.consume { hide ->
hideUI(hide)
@ -147,6 +159,27 @@ class VoipActivity : AppCompatActivity() {
target.slideInToastFromTopForDuration(binding.root as ViewGroup, lifecycleScope)
}
private fun showRedToast(message: String, @DrawableRes icon: Int) {
binding.redToast.message = message
binding.redToast.icon = icon
val target = binding.redToast.root
target.slideInToastFromTop(binding.root as ViewGroup, true)
}
private fun hideRedToast() {
val target = binding.redToast.root
target.slideInToastFromTop(binding.root as ViewGroup, false)
}
private fun showGreenToast(message: String, @DrawableRes icon: Int) {
binding.greenToast.message = message
binding.greenToast.icon = icon
val target = binding.greenToast.root
target.slideInToastFromTopForDuration(binding.root as ViewGroup, lifecycleScope, 2000)
}
private fun hideUI(hide: Boolean) {
Log.i("$TAG Switching full screen mode to ${if (hide) "ON" else "OFF"}")
val windowInsetsCompat = WindowInsetsControllerCompat(window, window.decorView)

View file

@ -24,6 +24,8 @@ import androidx.annotation.WorkerThread
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.core.Alert
import org.linphone.core.AlertListenerStub
import org.linphone.core.Call
import org.linphone.core.Core
import org.linphone.core.CoreListenerStub
@ -31,6 +33,10 @@ import org.linphone.core.tools.Log
import org.linphone.utils.Event
class CallsViewModel @UiThread constructor() : ViewModel() {
companion object {
private const val TAG = "[Calls ViewModel]"
}
val goToActiveCallEvent = MutableLiveData<Event<Boolean>>()
val showIncomingCallEvent = MutableLiveData<Event<Boolean>>()
@ -39,10 +45,25 @@ class CallsViewModel @UiThread constructor() : ViewModel() {
val noMoreCallEvent = MutableLiveData<Event<Boolean>>()
val showLowSignalEvent = MutableLiveData<Event<Boolean>>()
private val alertListener = object : AlertListenerStub() {
@WorkerThread
override fun onOnTerminated(alert: Alert) {
val remote = alert.call.remoteAddress.asStringUriOnly()
Log.w("$TAG Alert of type [${alert.type}] dismissed for call from [$remote]")
alert.removeListener(this)
if (alert.type == Alert.Type.QoSLowSignal) {
showLowSignalEvent.postValue(Event(false))
}
}
}
private val coreListener = object : CoreListenerStub() {
@WorkerThread
override fun onLastCallEnded(core: Core) {
Log.i("[Calls ViewModel] No more call, leaving VoIP activity")
Log.i("$TAG No more call, leaving VoIP activity")
noMoreCallEvent.postValue(Event(true))
}
@ -63,6 +84,17 @@ class CallsViewModel @UiThread constructor() : ViewModel() {
}
}
}
@WorkerThread
override fun onOnAlert(core: Core, alert: Alert) {
val remote = alert.call.remoteAddress.asStringUriOnly()
Log.w("$TAG Alert of type [${alert.type}] triggered for call from [$remote]")
alert.addListener(alertListener)
if (alert.type == Alert.Type.QoSLowSignal) {
showLowSignalEvent.postValue(Event(true))
}
}
}
init {
@ -82,10 +114,10 @@ class CallsViewModel @UiThread constructor() : ViewModel() {
Call.State.IncomingReceived, Call.State.IncomingEarlyMedia -> {
showIncomingCallEvent.postValue(Event(true))
}
else -> {
}
else -> {}
}
} else {
Log.w("$TAG No call found, leaving VoIP activity")
noMoreCallEvent.postValue(Event(true))
}
}

View file

@ -38,6 +38,10 @@ fun View.slideInToastFromTop(
visible: Boolean
) {
val view = this
if (visible && view.visibility == View.VISIBLE) {
// Toast is already visible, hide existing one first
view.visibility = View.GONE
}
val transition: Transition = Slide(Gravity.TOP)
transition.duration = 600
@ -51,7 +55,7 @@ fun View.slideInToastFromTop(
fun View.slideInToastFromTopForDuration(
root: ViewGroup,
lifecycleScope: LifecycleCoroutineScope,
duration: Long = 5000
duration: Long = 4000
) {
val view = this

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:radius="50dp" />
<solid android:color="@color/red_danger"/>
</shape>
</item>
<item android:bottom="2dp">
<shape android:shape="rectangle">
<corners android:radius="50dp" />
<solid
android:color="@color/white" />
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="96dp"
android:height="96dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M140,204a12,12 0,1 1,-12 -12A12,12 0,0 1,140 204ZM237.08,87A172,172 0,0 0,18.92 87,8 8,0 0,0 29.08,99.37a156,156 0,0 1,197.84 0A8,8 0,0 0,237.08 87ZM205,122.77a124,124 0,0 0,-153.94 0A8,8 0,0 0,61 135.31a108,108 0,0 1,134.06 0,8 8,0 0,0 11.24,-1.3A8,8 0,0 0,205 122.77ZM172.74,158.53a76.05,76.05 0,0 0,-89.42 0,8 8,0 0,0 9.42,12.94 60,60 0,0 1,70.58 0,8 8,0 1,0 9.42,-12.94Z"
android:fillColor="#4e6074"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="96dp"
android:height="96dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M140,204a12,12 0,1 1,-12 -12A12,12 0,0 1,140 204ZM172.71,158.53a76.05,76.05 0,0 0,-89.42 0,8 8,0 0,0 9.42,12.94 60,60 0,0 1,70.58 0,8 8,0 1,0 9.42,-12.94Z"
android:fillColor="#4e6074"/>
</vector>

View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<import type="android.graphics.Typeface" />
<variable
name="icon"
type="Integer" />
<variable
name="message"
type="String" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="17dp"
android:layout_marginEnd="17dp">
<ImageView
android:id="@+id/toast_background"
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@drawable/shape_toast_red_shadow"
app:layout_constraintBottom_toBottomOf="@id/toast_message"
app:layout_constraintEnd_toEndOf="@id/toast_message"
app:layout_constraintStart_toStartOf="@id/toast_icon"
app:layout_constraintTop_toTopOf="@id/toast_message" />
<ImageView
android:id="@+id/toast_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:adjustViewBounds="true"
android:src="@{icon, default=@drawable/wifi_low}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/toast_message"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:tint="@color/red_danger" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/toast_message"
style="@style/default_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:text="@{message, default=`Low Wi-Fi signal!`}"
android:textColor="@color/red_danger"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/toast_icon"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -37,6 +37,34 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<include
android:id="@+id/green_toast"
android:visibility="gone"
layout="@layout/toast_green"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/toast_top_margin"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
app:layout_constraintWidth_max="@dimen/toast_max_width"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<include
android:id="@+id/red_toast"
android:visibility="gone"
layout="@layout/toast_red"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/toast_top_margin"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
app:layout_constraintWidth_max="@dimen/toast_max_width"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>