popup window preview
This commit is contained in:
parent
f7bed719e3
commit
2ff2448739
16 changed files with 111 additions and 59 deletions
|
@ -8,6 +8,7 @@ import android.provider.ContactsContract
|
|||
import android.telecom.CallRedirectionService
|
||||
import android.telecom.PhoneAccountHandle
|
||||
import androidx.annotation.RequiresPermission
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class CallRedirectionService : CallRedirectionService() {
|
||||
companion object {
|
||||
|
@ -16,7 +17,7 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
private const val TELEGRAM_MIMETYPE = "$PREFIX/vnd.org.telegram.messenger.android.call"
|
||||
private const val THREEMA_MIMETYPE = "$PREFIX/vnd.ch.threema.app.call"
|
||||
private const val WHATSAPP_MIMETYPE = "$PREFIX/vnd.com.whatsapp.voip.call"
|
||||
private val MIMETYPES = mapOf(
|
||||
private val MIMETYPE_TO_WEIGHT = mapOf(
|
||||
SIGNAL_MIMETYPE to 0,
|
||||
TELEGRAM_MIMETYPE to 1,
|
||||
THREEMA_MIMETYPE to 2,
|
||||
|
@ -25,9 +26,15 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
private val FALLBACK_MIMETYPES = arrayOf(
|
||||
WHATSAPP_MIMETYPE,
|
||||
)
|
||||
private val MIMETYPE_TO_DST_NAME = mapOf(
|
||||
SIGNAL_MIMETYPE to R.string.destination_signal,
|
||||
TELEGRAM_MIMETYPE to R.string.destination_telegram,
|
||||
THREEMA_MIMETYPE to R.string.destination_threema,
|
||||
WHATSAPP_MIMETYPE to R.string.fallback_destination_whatsapp,
|
||||
)
|
||||
}
|
||||
|
||||
lateinit var prefs: Preferences
|
||||
private lateinit var prefs: Preferences
|
||||
private lateinit var window: PopupWindow
|
||||
private var connectivityManager: ConnectivityManager? = null
|
||||
|
||||
|
@ -43,7 +50,7 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
|
||||
private fun init() {
|
||||
prefs = Preferences(this)
|
||||
window = PopupWindow(this)
|
||||
window = PopupWindow(this, WeakReference(this))
|
||||
connectivityManager = getSystemService(ConnectivityManager::class.java)
|
||||
}
|
||||
|
||||
|
@ -52,7 +59,7 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
initialPhoneAccount: PhoneAccountHandle,
|
||||
allowInteractiveResponse: Boolean,
|
||||
) {
|
||||
if (!prefs.isServiceEnabled || !hasInternet() || !allowInteractiveResponse) {
|
||||
if (!prefs.isEnabled || !hasInternet() || !allowInteractiveResponse) {
|
||||
placeCallUnmodified()
|
||||
return
|
||||
}
|
||||
|
@ -63,18 +70,12 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
placeCallUnmodified()
|
||||
return
|
||||
}
|
||||
val record = records.minByOrNull { MIMETYPES[it.mimetype] ?: 0 }
|
||||
val record = records.minByOrNull { MIMETYPE_TO_WEIGHT[it.mimetype] ?: 0 }
|
||||
if (record == null || (record.mimetype in FALLBACK_MIMETYPES && !prefs.isFallbackChecked)) {
|
||||
placeCallUnmodified()
|
||||
return
|
||||
}
|
||||
window.show(record.uri, when (record.mimetype) {
|
||||
SIGNAL_MIMETYPE -> R.string.destination_signal
|
||||
TELEGRAM_MIMETYPE -> R.string.destination_telegram
|
||||
THREEMA_MIMETYPE -> R.string.destination_threema
|
||||
WHATSAPP_MIMETYPE -> R.string.fallback_destination_whatsapp
|
||||
else -> return
|
||||
})
|
||||
window.show(record.uri, MIMETYPE_TO_DST_NAME[record.mimetype] ?: return)
|
||||
}
|
||||
|
||||
@RequiresPermission(Manifest.permission.READ_CONTACTS)
|
||||
|
@ -83,7 +84,7 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
val cursor = contentResolver.query(
|
||||
Uri.withAppendedPath(
|
||||
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
|
||||
Uri.encode(phoneNumber)
|
||||
Uri.encode(phoneNumber),
|
||||
),
|
||||
arrayOf(ContactsContract.PhoneLookup._ID),
|
||||
null,
|
||||
|
@ -109,8 +110,8 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
arrayOf(ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE),
|
||||
"${ContactsContract.Data.CONTACT_ID} = ? AND " +
|
||||
"${ContactsContract.Data.MIMETYPE} IN " +
|
||||
"(${MIMETYPES.keys.joinToString(",") { "?" }})",
|
||||
arrayOf(contactId, *MIMETYPES.keys.toTypedArray()),
|
||||
"(${MIMETYPE_TO_WEIGHT.keys.joinToString(",") { "?" }})",
|
||||
arrayOf(contactId, *MIMETYPE_TO_WEIGHT.keys.toTypedArray()),
|
||||
null,
|
||||
)
|
||||
cursor?.apply {
|
||||
|
|
|
@ -23,6 +23,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var prefs: Preferences
|
||||
private lateinit var window: PopupWindow
|
||||
private var roleManager: RoleManager? = null
|
||||
|
||||
private val registerForCallRedirectionRole =
|
||||
|
@ -42,14 +43,20 @@ class MainActivity : AppCompatActivity() {
|
|||
setup()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
window.cancel()
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
prefs = Preferences(this)
|
||||
window = PopupWindow(this, null)
|
||||
roleManager = getSystemService(RoleManager::class.java)
|
||||
binding.apply {
|
||||
redirectionDelay.value = (prefs.redirectionDelay / 1000).toFloat()
|
||||
popupPosition.editText?.setText(prefs.popupPosition.toString())
|
||||
fallback.isChecked = prefs.isFallbackChecked
|
||||
toggle.isChecked = prefs.isServiceEnabled
|
||||
toggle.isChecked = prefs.isEnabled
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +68,9 @@ class MainActivity : AppCompatActivity() {
|
|||
redirectionDelay.addOnChangeListener { _, value, _ ->
|
||||
prefs.redirectionDelay = (value * 1000).toLong()
|
||||
}
|
||||
popupPosition.setEndIconOnClickListener {
|
||||
window.preview()
|
||||
}
|
||||
popupPosition.editText?.doAfterTextChanged {
|
||||
try {
|
||||
prefs.popupPosition = it?.toString()?.toInt() ?: return@doAfterTextChanged
|
||||
|
@ -75,7 +85,7 @@ class MainActivity : AppCompatActivity() {
|
|||
requestPermissions()
|
||||
return@setOnCheckedChangeListener
|
||||
}
|
||||
prefs.isServiceEnabled = isChecked
|
||||
prefs.isEnabled = isChecked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package me.lucky.red
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.PixelFormat
|
||||
import android.media.AudioManager
|
||||
|
@ -10,20 +11,19 @@ import android.view.LayoutInflater
|
|||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.RequiresPermission
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import kotlin.concurrent.timerTask
|
||||
|
||||
class PopupWindow(private val service: CallRedirectionService) {
|
||||
private val windowManager = service
|
||||
.applicationContext
|
||||
.getSystemService(WindowManager::class.java)
|
||||
private val audioManager = service
|
||||
.applicationContext
|
||||
.getSystemService(AudioManager::class.java)
|
||||
class PopupWindow(
|
||||
private val ctx: Context,
|
||||
private val service: WeakReference<CallRedirectionService>?,
|
||||
) {
|
||||
private val prefs = Preferences(ctx)
|
||||
private val windowManager = ctx.getSystemService(WindowManager::class.java)
|
||||
private val audioManager = ctx.getSystemService(AudioManager::class.java)
|
||||
@Suppress("InflateParams")
|
||||
private val view = LayoutInflater
|
||||
.from(service.applicationContext)
|
||||
.inflate(R.layout.popup, null)
|
||||
private val view = LayoutInflater.from(ctx).inflate(R.layout.popup, null)
|
||||
private val layoutParams = WindowManager.LayoutParams().apply {
|
||||
format = PixelFormat.TRANSLUCENT
|
||||
flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
|
@ -31,18 +31,32 @@ class PopupWindow(private val service: CallRedirectionService) {
|
|||
gravity = Gravity.BOTTOM
|
||||
width = WindowManager.LayoutParams.WRAP_CONTENT
|
||||
height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||
y = service.prefs.popupPosition
|
||||
y = prefs.popupPosition
|
||||
}
|
||||
private var timer: Timer? = null
|
||||
|
||||
init {
|
||||
view.setOnClickListener {
|
||||
cancel()
|
||||
service.placeCallUnmodified()
|
||||
service?.get()?.placeCallUnmodified()
|
||||
}
|
||||
}
|
||||
|
||||
fun preview() {
|
||||
remove()
|
||||
layoutParams.y = prefs.popupPosition
|
||||
val destinations = mutableListOf(
|
||||
R.string.destination_signal,
|
||||
R.string.destination_telegram,
|
||||
R.string.destination_threema,
|
||||
)
|
||||
if (prefs.isFallbackChecked) destinations.add(R.string.fallback_destination_whatsapp)
|
||||
setDescription(destinations.random())
|
||||
add()
|
||||
}
|
||||
|
||||
fun show(uri: Uri, destinationId: Int) {
|
||||
val service = service?.get() ?: return
|
||||
if (!remove()) {
|
||||
service.placeCallUnmodified()
|
||||
return
|
||||
|
@ -65,23 +79,27 @@ class PopupWindow(private val service: CallRedirectionService) {
|
|||
return@timerTask
|
||||
}
|
||||
service.cancelCall()
|
||||
}, service.prefs.redirectionDelay)
|
||||
view.findViewById<TextView>(R.id.description).text = String.format(
|
||||
service.getString(R.string.popup),
|
||||
service.getString(destinationId),
|
||||
)
|
||||
}, prefs.redirectionDelay)
|
||||
setDescription(destinationId)
|
||||
if (!add()) {
|
||||
timer?.cancel()
|
||||
service.placeCallUnmodified()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setDescription(id: Int) {
|
||||
view.findViewById<TextView>(R.id.description).text = ctx.getString(
|
||||
R.string.popup,
|
||||
ctx.getString(id),
|
||||
)
|
||||
}
|
||||
|
||||
@RequiresPermission(Manifest.permission.CALL_PHONE)
|
||||
private fun call(data: Uri) {
|
||||
Intent(Intent.ACTION_VIEW).let {
|
||||
it.data = data
|
||||
it.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
service.startActivity(it)
|
||||
ctx.startActivity(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,20 +6,23 @@ import androidx.preference.PreferenceManager
|
|||
|
||||
class Preferences(ctx: Context) {
|
||||
companion object {
|
||||
private const val SERVICE_ENABLED = "service_enabled"
|
||||
private const val ENABLED = "enabled"
|
||||
private const val REDIRECTION_DELAY = "redirection_delay"
|
||||
private const val POPUP_POSITION = "popup_position_y"
|
||||
private const val FALLBACK_CHECKED = "fallback_checked"
|
||||
|
||||
private const val DEFAULT_REDIRECTION_DELAY = 2000L
|
||||
private const val DEFAULT_POPUP_POSITION = 333
|
||||
|
||||
// migration
|
||||
private const val SERVICE_ENABLED = "service_enabled"
|
||||
}
|
||||
|
||||
private val prefs = PreferenceManager.getDefaultSharedPreferences(ctx)
|
||||
|
||||
var isServiceEnabled: Boolean
|
||||
get() = prefs.getBoolean(SERVICE_ENABLED, false)
|
||||
set(value) = prefs.edit { putBoolean(SERVICE_ENABLED, value) }
|
||||
var isEnabled: Boolean
|
||||
get() = prefs.getBoolean(ENABLED, prefs.getBoolean(SERVICE_ENABLED, false))
|
||||
set(value) = prefs.edit { putBoolean(ENABLED, value) }
|
||||
|
||||
var redirectionDelay: Long
|
||||
get() = prefs.getLong(REDIRECTION_DELAY, DEFAULT_REDIRECTION_DELAY)
|
||||
|
|
10
app/src/main/res/drawable/ic_baseline_check_circle_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_check_circle_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
|
||||
</vector>
|
|
@ -55,6 +55,8 @@
|
|||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/popupPosition"
|
||||
app:endIconMode="custom"
|
||||
app:endIconDrawable="@drawable/ic_baseline_check_circle_24"
|
||||
android:hint="@string/popup_position"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<string name="destination_signal">Signal</string>
|
||||
<string name="destination_telegram">Telegram</string>
|
||||
<string name="destination_threema">Threema</string>
|
||||
<string name="redirection_delay_description">Delay before a call will be redirected.</string>
|
||||
<string name="redirection_delay_description">The delay before a call will be redirected.</string>
|
||||
<string name="popup_position">Popup position</string>
|
||||
<string name="fallback">Fallback</string>
|
||||
<string name="fallback_description">Redirect to WhatsApp if no other available.</string>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue