Import some classes from Element into :libraries:androidutils
This commit is contained in:
parent
5421957b8e
commit
049c25e434
10 changed files with 442 additions and 2 deletions
|
|
@ -16,7 +16,7 @@ datastore = "1.0.0"
|
||||||
constraintlayout = "2.1.4"
|
constraintlayout = "2.1.4"
|
||||||
recyclerview = "1.3.0"
|
recyclerview = "1.3.0"
|
||||||
lifecycle = "2.5.1"
|
lifecycle = "2.5.1"
|
||||||
activity_compose = "1.6.1"
|
activity = "1.6.1"
|
||||||
startup = "1.1.1"
|
startup = "1.1.1"
|
||||||
|
|
||||||
# Compose
|
# Compose
|
||||||
|
|
@ -70,7 +70,8 @@ androidx_lifecycle_process = { module = "androidx.lifecycle:lifecycle-process",
|
||||||
androidx_splash = "androidx.core:core-splashscreen:1.0.0"
|
androidx_splash = "androidx.core:core-splashscreen:1.0.0"
|
||||||
androidx_security_crypto = "androidx.security:security-crypto:1.0.0"
|
androidx_security_crypto = "androidx.security:security-crypto:1.0.0"
|
||||||
|
|
||||||
androidx_activity_compose = { module = "androidx.activity:activity-compose", version.ref = "activity_compose" }
|
androidx_activity_activity = { module = "androidx.activity:activity", version.ref = "activity" }
|
||||||
|
androidx_activity_compose = { module = "androidx.activity:activity-compose", version.ref = "activity" }
|
||||||
androidx_startup = { module = "androidx.startup:startup-runtime", version.ref = "startup" }
|
androidx_startup = { module = "androidx.startup:startup-runtime", version.ref = "startup" }
|
||||||
|
|
||||||
androidx_compose_bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose_bom" }
|
androidx_compose_bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose_bom" }
|
||||||
|
|
|
||||||
|
|
@ -26,5 +26,6 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.timber)
|
implementation(libs.timber)
|
||||||
implementation(libs.androidx.corektx)
|
implementation(libs.androidx.corektx)
|
||||||
|
implementation(libs.androidx.activity.activity)
|
||||||
implementation(projects.libraries.core)
|
implementation(projects.libraries.core)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,5 @@
|
||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.androidutils.compat
|
||||||
|
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
|
||||||
|
fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): ApplicationInfo {
|
||||||
|
return when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getApplicationInfo(
|
||||||
|
packageName,
|
||||||
|
PackageManager.ApplicationInfoFlags.of(flags.toLong())
|
||||||
|
)
|
||||||
|
else -> @Suppress("DEPRECATION") getApplicationInfo(packageName, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int): PackageInfo {
|
||||||
|
return when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getPackageInfo(
|
||||||
|
packageName,
|
||||||
|
PackageManager.PackageInfoFlags.of(flags.toLong())
|
||||||
|
)
|
||||||
|
else -> @Suppress("DEPRECATION") getPackageInfo(packageName, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.androidutils.intent
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.os.Build
|
||||||
|
|
||||||
|
object PendingIntentCompat {
|
||||||
|
const val FLAG_IMMUTABLE = PendingIntent.FLAG_IMMUTABLE
|
||||||
|
|
||||||
|
val FLAG_MUTABLE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
PendingIntent.FLAG_MUTABLE
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.androidutils.network
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
import io.element.android.libraries.core.bool.orFalse
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class WifiDetector(
|
||||||
|
context: Context
|
||||||
|
) {
|
||||||
|
private val connectivityManager = context.getSystemService<ConnectivityManager>()!!
|
||||||
|
|
||||||
|
fun isConnectedToWifi(): Boolean {
|
||||||
|
return connectivityManager.activeNetwork
|
||||||
|
?.let { connectivityManager.getNetworkCapabilities(it) }
|
||||||
|
?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|
||||||
|
.orFalse()
|
||||||
|
.also { Timber.d("isConnected to WiFi: $it") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.androidutils.system
|
||||||
|
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
|
||||||
|
class CopyToClipboardUseCase(
|
||||||
|
private val context: Context,
|
||||||
|
) {
|
||||||
|
fun execute(text: CharSequence) {
|
||||||
|
context.getSystemService<ClipboardManager>()
|
||||||
|
?.setPrimaryClip(ClipData.newPlainText("", text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,221 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.androidutils.system
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.PowerManager
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.annotation.ChecksSdkIntAtLeast
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
import io.element.android.libraries.androidutils.compat.getApplicationInfoCompat
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the application ignores battery optimizations.
|
||||||
|
*
|
||||||
|
* Ignoring them allows the app to run in background to make background sync with the homeserver.
|
||||||
|
* This user option appears on Android M but Android O enforces its usage and kills apps not
|
||||||
|
* authorised by the user to run in background.
|
||||||
|
*
|
||||||
|
* @return true if battery optimisations are ignored
|
||||||
|
*/
|
||||||
|
fun Context.isIgnoringBatteryOptimizations(): Boolean {
|
||||||
|
// no issue before Android M, battery optimisations did not exist
|
||||||
|
return getSystemService<PowerManager>()?.isIgnoringBatteryOptimizations(packageName) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.isAirplaneModeOn(): Boolean {
|
||||||
|
return Settings.Global.getInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.isAnimationEnabled(): Boolean {
|
||||||
|
return Settings.Global.getFloat(contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f) != 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O)
|
||||||
|
fun supportNotificationChannels() = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the application label of the provided package. If not found, the package is returned.
|
||||||
|
*/
|
||||||
|
fun Context.getApplicationLabel(packageName: String): String {
|
||||||
|
return try {
|
||||||
|
val ai = packageManager.getApplicationInfoCompat(packageName, 0)
|
||||||
|
packageManager.getApplicationLabel(ai).toString()
|
||||||
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
|
packageName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* display the system dialog for granting this permission. If previously granted, the
|
||||||
|
* system will not show it (so you should call this method).
|
||||||
|
*
|
||||||
|
* Note: If the user finally does not grant the permission, PushManager.isBackgroundSyncAllowed()
|
||||||
|
* will return false and the notification privacy will fallback to "LOW_DETAIL".
|
||||||
|
*/
|
||||||
|
fun requestDisablingBatteryOptimization(activity: Activity, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
|
val intent = Intent()
|
||||||
|
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||||
|
intent.data = Uri.parse("package:" + activity.packageName)
|
||||||
|
activityResultLauncher.launch(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================================================================================
|
||||||
|
// Clipboard helper
|
||||||
|
// ==============================================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy a text to the clipboard, and display a Toast when done.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param text the text to copy
|
||||||
|
* @param toastMessage content of the toast message as a String resource. Null for no toast
|
||||||
|
*/
|
||||||
|
fun copyToClipboard(
|
||||||
|
context: Context,
|
||||||
|
text: CharSequence,
|
||||||
|
toastMessage: String? = null
|
||||||
|
) {
|
||||||
|
CopyToClipboardUseCase(context).execute(text)
|
||||||
|
toastMessage?.let { context.toast(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows notification settings for the current app.
|
||||||
|
* In android O will directly opens the notification settings, in lower version it will show the App settings
|
||||||
|
*/
|
||||||
|
fun startNotificationSettingsIntent(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
|
val intent = Intent()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||||
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
|
||||||
|
} else {
|
||||||
|
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||||
|
intent.putExtra("app_package", context.packageName)
|
||||||
|
intent.putExtra("app_uid", context.applicationInfo?.uid)
|
||||||
|
}
|
||||||
|
activityResultLauncher.launch(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows notification system settings for the given channel id.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
|
fun startNotificationChannelSettingsIntent(activity: Activity, channelID: String) {
|
||||||
|
if (!supportNotificationChannels()) return
|
||||||
|
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply {
|
||||||
|
putExtra(Settings.EXTRA_APP_PACKAGE, activity.packageName)
|
||||||
|
putExtra(Settings.EXTRA_CHANNEL_ID, channelID)
|
||||||
|
}
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startAddGoogleAccountIntent(
|
||||||
|
context: Context,
|
||||||
|
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||||
|
noActivityFoundMessage: String,
|
||||||
|
) {
|
||||||
|
val intent = Intent(Settings.ACTION_ADD_ACCOUNT)
|
||||||
|
intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, arrayOf("com.google"))
|
||||||
|
try {
|
||||||
|
activityResultLauncher.launch(intent)
|
||||||
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
|
context.toast(noActivityFoundMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
fun startInstallFromSourceIntent(
|
||||||
|
context: Context,
|
||||||
|
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||||
|
noActivityFoundMessage: String,
|
||||||
|
) {
|
||||||
|
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
|
||||||
|
.setData(Uri.parse(String.format("package:%s", context.packageName)))
|
||||||
|
try {
|
||||||
|
activityResultLauncher.launch(intent)
|
||||||
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
|
context.toast(noActivityFoundMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startSharePlainTextIntent(
|
||||||
|
context: Context,
|
||||||
|
activityResultLauncher: ActivityResultLauncher<Intent>?,
|
||||||
|
chooserTitle: String?,
|
||||||
|
text: String,
|
||||||
|
subject: String? = null,
|
||||||
|
extraTitle: String? = null,
|
||||||
|
noActivityFoundMessage: String,
|
||||||
|
) {
|
||||||
|
val share = Intent(Intent.ACTION_SEND)
|
||||||
|
share.type = "text/plain"
|
||||||
|
share.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
|
||||||
|
// Add data to the intent, the receiving app will decide what to do with it.
|
||||||
|
share.putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||||
|
share.putExtra(Intent.EXTRA_TEXT, text)
|
||||||
|
|
||||||
|
extraTitle?.let {
|
||||||
|
share.putExtra(Intent.EXTRA_TITLE, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val intent = Intent.createChooser(share, chooserTitle)
|
||||||
|
try {
|
||||||
|
if (activityResultLauncher != null) {
|
||||||
|
activityResultLauncher.launch(intent)
|
||||||
|
} else {
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
|
context.toast(noActivityFoundMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startImportTextFromFileIntent(
|
||||||
|
context: Context,
|
||||||
|
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||||
|
noActivityFoundMessage: String,
|
||||||
|
) {
|
||||||
|
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||||
|
type = "text/plain"
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
activityResultLauncher.launch(intent)
|
||||||
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
|
context.toast(noActivityFoundMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not in KTX anymore
|
||||||
|
fun Context.toast(resId: Int) {
|
||||||
|
Toast.makeText(this, resId, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not in KTX anymore
|
||||||
|
fun Context.toast(message: String) {
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.element.android.libraries.androidutils.throttler
|
||||||
|
|
||||||
|
import android.os.SystemClock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple ThrottleFirst
|
||||||
|
* See https://raw.githubusercontent.com/wiki/ReactiveX/RxJava/images/rx-operators/throttleFirst.png
|
||||||
|
*/
|
||||||
|
class FirstThrottler(private val minimumInterval: Long = 800) {
|
||||||
|
private var lastDate = 0L
|
||||||
|
|
||||||
|
sealed class CanHandlerResult {
|
||||||
|
object Yes : CanHandlerResult()
|
||||||
|
data class No(val shouldWaitMillis: Long) : CanHandlerResult()
|
||||||
|
|
||||||
|
fun waitMillis(): Long {
|
||||||
|
return when (this) {
|
||||||
|
Yes -> 0
|
||||||
|
is No -> shouldWaitMillis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun canHandle(): CanHandlerResult {
|
||||||
|
val now = SystemClock.elapsedRealtime()
|
||||||
|
val delaySinceLast = now - lastDate
|
||||||
|
if (delaySinceLast > minimumInterval) {
|
||||||
|
lastDate = now
|
||||||
|
return CanHandlerResult.Yes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Too soon
|
||||||
|
return CanHandlerResult.No(minimumInterval - delaySinceLast)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.androidutils.uri
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
const val IGNORED_SCHEMA = "ignored"
|
||||||
|
|
||||||
|
fun Uri.isIgnored() = scheme == IGNORED_SCHEMA
|
||||||
|
|
||||||
|
fun createIgnoredUri(path: String): Uri = Uri.parse("$IGNORED_SCHEMA://$path")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue