Merge pull request #1872 from vector-im/feature/bma/removeDeadCode
Remove unused code to increase code coverage.
This commit is contained in:
commit
951f1d516f
9 changed files with 2 additions and 298 deletions
|
|
@ -21,5 +21,4 @@ package io.element.android.libraries.androidutils.clipboard
|
||||||
*/
|
*/
|
||||||
interface ClipboardHelper {
|
interface ClipboardHelper {
|
||||||
fun copyPlainText(text: String)
|
fun copyPlainText(text: String)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,26 +17,15 @@
|
||||||
package io.element.android.libraries.androidutils.compat
|
package io.element.android.libraries.androidutils.compat
|
||||||
|
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageInfo
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
|
||||||
fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): ApplicationInfo {
|
fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): ApplicationInfo {
|
||||||
return when {
|
return when {
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getApplicationInfo(
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getApplicationInfo(
|
||||||
packageName,
|
packageName,
|
||||||
PackageManager.ApplicationInfoFlags.of(flags.toLong())
|
PackageManager.ApplicationInfoFlags.of(flags.toLong())
|
||||||
)
|
)
|
||||||
else -> @Suppress("DEPRECATION") getApplicationInfo(packageName, flags)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.extensions
|
|
||||||
|
|
||||||
import android.util.Patterns
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a CharSequence is an email.
|
|
||||||
*/
|
|
||||||
fun CharSequence.isEmail() = Patterns.EMAIL_ADDRESS.matcher(this).matches()
|
|
||||||
|
|
@ -21,7 +21,6 @@ import androidx.annotation.WorkerThread
|
||||||
import io.element.android.libraries.core.data.tryOrNull
|
import io.element.android.libraries.core.data.tryOrNull
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Locale
|
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
fun File.safeDelete() {
|
fun File.safeDelete() {
|
||||||
|
|
@ -56,88 +55,6 @@ fun Context.createTmpFile(baseDir: File = cacheDir, extension: String? = null):
|
||||||
return File.createTempFile(UUID.randomUUID().toString(), suffix, baseDir).apply { mkdirs() }
|
return File.createTempFile(UUID.randomUUID().toString(), suffix, baseDir).apply { mkdirs() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation should return true in case of success
|
|
||||||
typealias ActionOnFile = (file: File) -> Boolean
|
|
||||||
|
|
||||||
/* ==========================================================================================
|
|
||||||
* Log
|
|
||||||
* ========================================================================================== */
|
|
||||||
|
|
||||||
fun lsFiles(context: Context) {
|
|
||||||
Timber.v("Content of cache dir:")
|
|
||||||
recursiveActionOnFile(context.cacheDir, ::logAction)
|
|
||||||
|
|
||||||
Timber.v("Content of files dir:")
|
|
||||||
recursiveActionOnFile(context.filesDir, ::logAction)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun logAction(file: File): Boolean {
|
|
||||||
if (file.isDirectory) {
|
|
||||||
Timber.v(file.toString())
|
|
||||||
} else {
|
|
||||||
Timber.v("$file ${file.length()} bytes")
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================================
|
|
||||||
* Private
|
|
||||||
* ========================================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true in case of success.
|
|
||||||
*/
|
|
||||||
private fun recursiveActionOnFile(file: File, action: ActionOnFile): Boolean {
|
|
||||||
if (file.isDirectory) {
|
|
||||||
file.list()?.forEach {
|
|
||||||
val result = recursiveActionOnFile(File(file, it), action)
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
// Break the loop
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return action.invoke(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the file extension of a fileUri or a filename.
|
|
||||||
*
|
|
||||||
* @param fileUri the fileUri (can be a simple filename)
|
|
||||||
* @return the file extension, in lower case, or null is extension is not available or empty
|
|
||||||
*/
|
|
||||||
fun getFileExtension(fileUri: String): String? {
|
|
||||||
var reducedStr = fileUri
|
|
||||||
|
|
||||||
if (reducedStr.isNotEmpty()) {
|
|
||||||
// Remove fragment
|
|
||||||
reducedStr = reducedStr.substringBeforeLast('#')
|
|
||||||
|
|
||||||
// Remove query
|
|
||||||
reducedStr = reducedStr.substringBeforeLast('?')
|
|
||||||
|
|
||||||
// Remove path
|
|
||||||
val filename = reducedStr.substringAfterLast('/')
|
|
||||||
|
|
||||||
// Contrary to method MimeTypeMap.getFileExtensionFromUrl, we do not check the pattern
|
|
||||||
// See https://stackoverflow.com/questions/14320527/android-should-i-use-mimetypemap-getfileextensionfromurl-bugs
|
|
||||||
if (filename.isNotEmpty()) {
|
|
||||||
val dotPos = filename.lastIndexOf('.')
|
|
||||||
if (0 <= dotPos) {
|
|
||||||
val ext = filename.substring(dotPos + 1)
|
|
||||||
|
|
||||||
if (ext.isNotBlank()) {
|
|
||||||
return ext.lowercase(Locale.ROOT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* Size
|
* Size
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* 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") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,48 +16,22 @@
|
||||||
|
|
||||||
package io.element.android.libraries.androidutils.system
|
package io.element.android.libraries.androidutils.system
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.PowerManager
|
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.annotation.ChecksSdkIntAtLeast
|
import androidx.annotation.ChecksSdkIntAtLeast
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.getSystemService
|
|
||||||
import io.element.android.libraries.androidutils.R
|
import io.element.android.libraries.androidutils.R
|
||||||
import io.element.android.libraries.androidutils.compat.getApplicationInfoCompat
|
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)
|
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O)
|
||||||
fun supportNotificationChannels() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
fun supportNotificationChannels() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||||
|
|
||||||
|
|
@ -73,32 +47,6 @@ fun Context.getApplicationLabel(packageName: String): String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true it the user has enabled the do not disturb mode.
|
|
||||||
*/
|
|
||||||
fun Context.isDoNotDisturbModeOn(): Boolean {
|
|
||||||
// We cannot use NotificationManagerCompat here.
|
|
||||||
val setting = getSystemService<NotificationManager>()!!.currentInterruptionFilter
|
|
||||||
|
|
||||||
return setting == NotificationManager.INTERRUPTION_FILTER_NONE ||
|
|
||||||
setting == NotificationManager.INTERRUPTION_FILTER_ALARMS
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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".
|
|
||||||
*/
|
|
||||||
@SuppressLint("BatteryLife")
|
|
||||||
fun Context.requestDisablingBatteryOptimization(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
|
||||||
val intent = Intent()
|
|
||||||
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
|
||||||
intent.data = Uri.parse("package:$packageName")
|
|
||||||
activityResultLauncher.launch(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
// Clipboard helper
|
// Clipboard helper
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
|
|
@ -169,19 +117,6 @@ fun Activity.startNotificationChannelSettingsIntent(channelID: String) {
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.startAddGoogleAccountIntent(
|
|
||||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
|
||||||
noActivityFoundMessage: String = getString(R.string.error_no_compatible_app_found),
|
|
||||||
) {
|
|
||||||
val intent = Intent(Settings.ACTION_ADD_ACCOUNT)
|
|
||||||
intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, arrayOf("com.google"))
|
|
||||||
try {
|
|
||||||
activityResultLauncher.launch(intent)
|
|
||||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
|
||||||
toast(noActivityFoundMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
fun Context.startInstallFromSourceIntent(
|
fun Context.startInstallFromSourceIntent(
|
||||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||||
|
|
@ -227,20 +162,6 @@ fun Context.startSharePlainTextIntent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.startImportTextFromFileIntent(
|
|
||||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
|
||||||
noActivityFoundMessage: String = getString(R.string.error_no_compatible_app_found),
|
|
||||||
) {
|
|
||||||
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
|
|
||||||
type = "text/plain"
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
activityResultLauncher.launch(intent)
|
|
||||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
|
||||||
toast(noActivityFoundMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("SwallowedException")
|
@Suppress("SwallowedException")
|
||||||
fun Context.openUrlInExternalApp(
|
fun Context.openUrlInExternalApp(
|
||||||
url: String,
|
url: String,
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.ui
|
|
||||||
|
|
||||||
import android.content.res.Resources
|
|
||||||
import android.util.TypedValue
|
|
||||||
import androidx.annotation.Px
|
|
||||||
|
|
||||||
class DimensionConverter(private val resources: Resources) {
|
|
||||||
|
|
||||||
@Px
|
|
||||||
fun dpToPx(dp: Int): Int {
|
|
||||||
return TypedValue.applyDimension(
|
|
||||||
TypedValue.COMPLEX_UNIT_DIP,
|
|
||||||
dp.toFloat(),
|
|
||||||
resources.displayMetrics
|
|
||||||
).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Px
|
|
||||||
fun spToPx(sp: Int): Int {
|
|
||||||
return TypedValue.applyDimension(
|
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
|
||||||
sp.toFloat(),
|
|
||||||
resources.displayMetrics
|
|
||||||
).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun pxToDp(@Px px: Int): Int {
|
|
||||||
return (px.toFloat() / resources.displayMetrics.density).toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -36,15 +36,6 @@ fun View.showKeyboard(andRequestFocus: Boolean = false) {
|
||||||
imm?.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
|
imm?.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun View.setHorizontalPadding(padding: Int) {
|
|
||||||
setPadding(
|
|
||||||
padding,
|
|
||||||
paddingTop,
|
|
||||||
padding,
|
|
||||||
paddingBottom
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun View.awaitWindowFocus() = suspendCancellableCoroutine { continuation ->
|
suspend fun View.awaitWindowFocus() = suspendCancellableCoroutine { continuation ->
|
||||||
if (hasWindowFocus()) {
|
if (hasWindowFocus()) {
|
||||||
continuation.resume(Unit)
|
continuation.resume(Unit)
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,6 @@ package io.element.android.libraries.androidutils.uri
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
|
||||||
const val ASSET_FILE_PATH_ROOT = "android_asset"
|
|
||||||
const val IGNORED_SCHEMA = "ignored"
|
const val IGNORED_SCHEMA = "ignored"
|
||||||
|
|
||||||
fun Uri.isIgnored() = scheme == IGNORED_SCHEMA
|
|
||||||
|
|
||||||
fun createIgnoredUri(path: String): Uri = Uri.parse("$IGNORED_SCHEMA://$path")
|
fun createIgnoredUri(path: String): Uri = Uri.parse("$IGNORED_SCHEMA://$path")
|
||||||
|
|
||||||
val Uri.firstPathSegment: String?
|
|
||||||
get() = pathSegments.firstOrNull()
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue