mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Merge pull request #1948 from tilosp/api-21-cleanup
Remove old code that was used on devices with api level <21
This commit is contained in:
commit
8581d06931
@ -33,6 +33,7 @@ Other changes:
|
||||
- Rename package `im.vector.riotx.attachmentviewer` to `im.vector.lib.attachmentviewer`
|
||||
- Rename package `im.vector.riotx.multipicker` to `im.vector.lib.multipicker`
|
||||
- Rename package `im.vector.riotx` to `im.vector.app`
|
||||
- Remove old code that was used on devices with api level <21
|
||||
- Add Official Gradle Wrapper Validation Action
|
||||
|
||||
Changes in Element 1.0.4 (2020-08-03)
|
||||
|
@ -29,5 +29,6 @@
|
||||
<issue id="SetTextI18n" severity="error" />
|
||||
<issue id="ViewConstructor" severity="error" />
|
||||
<issue id="UseValueOf" severity="error" />
|
||||
<issue id="ObsoleteSdkInt" severity="error" />
|
||||
|
||||
</lint>
|
||||
|
@ -18,7 +18,6 @@
|
||||
package org.matrix.android.sdk.internal.crypto.store.db
|
||||
|
||||
import android.util.Base64
|
||||
import org.matrix.android.sdk.internal.util.CompatUtil
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmObject
|
||||
@ -26,6 +25,7 @@ import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.ObjectOutputStream
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
|
||||
/**
|
||||
* Get realm, invoke the action, close realm, and return the result of the action
|
||||
@ -78,7 +78,7 @@ fun serializeForRealm(o: Any?): String? {
|
||||
}
|
||||
|
||||
val baos = ByteArrayOutputStream()
|
||||
val gzis = CompatUtil.createGzipOutputStream(baos)
|
||||
val gzis = GZIPOutputStream(baos)
|
||||
val out = ObjectOutputStream(gzis)
|
||||
out.use {
|
||||
it.writeObject(o)
|
||||
|
@ -44,10 +44,7 @@ import javax.crypto.CipherInputStream
|
||||
import javax.crypto.CipherOutputStream
|
||||
import javax.crypto.KeyGenerator
|
||||
import javax.crypto.SecretKey
|
||||
import javax.crypto.SecretKeyFactory
|
||||
import javax.crypto.spec.GCMParameterSpec
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.PBEKeySpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import javax.inject.Inject
|
||||
import javax.security.auth.x500.X500Principal
|
||||
@ -127,9 +124,8 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
@Throws(Exception::class)
|
||||
fun securelyStoreString(secret: String, keyAlias: String): ByteArray? {
|
||||
return when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> encryptStringM(secret, keyAlias)
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> encryptStringK(secret, keyAlias)
|
||||
else -> encryptForOldDevicesNotGood(secret, keyAlias)
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> encryptStringM(secret, keyAlias)
|
||||
else -> encryptString(secret, keyAlias)
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,25 +135,22 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
@Throws(Exception::class)
|
||||
fun loadSecureSecret(encrypted: ByteArray, keyAlias: String): String? {
|
||||
return when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> decryptStringM(encrypted, keyAlias)
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> decryptStringK(encrypted, keyAlias)
|
||||
else -> decryptForOldDevicesNotGood(encrypted, keyAlias)
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> decryptStringM(encrypted, keyAlias)
|
||||
else -> decryptString(encrypted, keyAlias)
|
||||
}
|
||||
}
|
||||
|
||||
fun securelyStoreObject(any: Any, keyAlias: String, output: OutputStream) {
|
||||
when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> saveSecureObjectM(keyAlias, output, any)
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> saveSecureObjectK(keyAlias, output, any)
|
||||
else -> saveSecureObjectOldNotGood(keyAlias, output, any)
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> saveSecureObjectM(keyAlias, output, any)
|
||||
else -> saveSecureObject(keyAlias, output, any)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> loadSecureSecret(inputStream: InputStream, keyAlias: String): T? {
|
||||
return when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> loadSecureObjectM(keyAlias, inputStream)
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> loadSecureObjectK(keyAlias, inputStream)
|
||||
else -> loadSecureObjectOldNotGood(keyAlias, inputStream)
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> loadSecureObjectM(keyAlias, inputStream)
|
||||
else -> loadSecureObject(keyAlias, inputStream)
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,7 +181,6 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
- Store the encrypted AES
|
||||
Generate a key pair for encryption
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
fun getOrGenerateKeyPairForAlias(alias: String): KeyStore.PrivateKeyEntry {
|
||||
val privateKeyEntry = (keyStore.getEntry(alias, null) as? KeyStore.PrivateKeyEntry)
|
||||
|
||||
@ -238,8 +230,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
return String(cipher.doFinal(encryptedText), Charsets.UTF_8)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
private fun encryptStringK(text: String, keyAlias: String): ByteArray? {
|
||||
private fun encryptString(text: String, keyAlias: String): ByteArray? {
|
||||
// we generate a random symmetric key
|
||||
val key = ByteArray(16)
|
||||
secureRandom.nextBytes(key)
|
||||
@ -256,47 +247,13 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
return format1Make(encryptedKey, iv, encryptedBytes)
|
||||
}
|
||||
|
||||
private fun encryptForOldDevicesNotGood(text: String, keyAlias: String): ByteArray {
|
||||
val salt = ByteArray(8)
|
||||
secureRandom.nextBytes(salt)
|
||||
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||
val spec = PBEKeySpec(keyAlias.toCharArray(), salt, 10000, 128)
|
||||
val tmp = factory.generateSecret(spec)
|
||||
val sKey = SecretKeySpec(tmp.encoded, "AES")
|
||||
|
||||
val cipher = Cipher.getInstance(AES_MODE)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, sKey)
|
||||
val iv = cipher.iv
|
||||
val encryptedBytes: ByteArray = cipher.doFinal(text.toByteArray(Charsets.UTF_8))
|
||||
|
||||
return format2Make(salt, iv, encryptedBytes)
|
||||
}
|
||||
|
||||
private fun decryptForOldDevicesNotGood(data: ByteArray, keyAlias: String): String? {
|
||||
val (salt, iv, encrypted) = format2Extract(ByteArrayInputStream(data))
|
||||
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||
val spec = PBEKeySpec(keyAlias.toCharArray(), salt, 10_000, 128)
|
||||
val tmp = factory.generateSecret(spec)
|
||||
val sKey = SecretKeySpec(tmp.encoded, "AES")
|
||||
|
||||
val cipher = Cipher.getInstance(AES_MODE)
|
||||
// cipher.init(Cipher.ENCRYPT_MODE, sKey)
|
||||
// val encryptedBytes: ByteArray = cipher.doFinal(text.toByteArray(Charsets.UTF_8))
|
||||
|
||||
val specIV = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv)
|
||||
cipher.init(Cipher.DECRYPT_MODE, sKey, specIV)
|
||||
|
||||
return String(cipher.doFinal(encrypted), Charsets.UTF_8)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
private fun decryptStringK(data: ByteArray, keyAlias: String): String? {
|
||||
private fun decryptString(data: ByteArray, keyAlias: String): String? {
|
||||
val (encryptedKey, iv, encrypted) = format1Extract(ByteArrayInputStream(data))
|
||||
|
||||
// we need to decrypt the key
|
||||
val sKeyBytes = rsaDecrypt(keyAlias, ByteArrayInputStream(encryptedKey))
|
||||
val cipher = Cipher.getInstance(AES_MODE)
|
||||
val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv)
|
||||
val spec = GCMParameterSpec(128, iv)
|
||||
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(sKeyBytes, "AES"), spec)
|
||||
|
||||
return String(cipher.doFinal(encrypted), Charsets.UTF_8)
|
||||
@ -323,8 +280,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
output.write(doFinal)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
private fun saveSecureObjectK(keyAlias: String, output: OutputStream, writeObject: Any) {
|
||||
private fun saveSecureObject(keyAlias: String, output: OutputStream, writeObject: Any) {
|
||||
// we generate a random symmetric key
|
||||
val key = ByteArray(16)
|
||||
secureRandom.nextBytes(key)
|
||||
@ -352,32 +308,6 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
output.write(bos1.toByteArray())
|
||||
}
|
||||
|
||||
private fun saveSecureObjectOldNotGood(keyAlias: String, output: OutputStream, writeObject: Any) {
|
||||
val salt = ByteArray(8)
|
||||
secureRandom.nextBytes(salt)
|
||||
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||
val tmp = factory.generateSecret(PBEKeySpec(keyAlias.toCharArray(), salt, 10000, 128))
|
||||
val secretKey = SecretKeySpec(tmp.encoded, "AES")
|
||||
|
||||
val cipher = Cipher.getInstance(AES_MODE)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
|
||||
val iv = cipher.iv
|
||||
|
||||
val bos1 = ByteArrayOutputStream()
|
||||
ObjectOutputStream(bos1).use {
|
||||
it.writeObject(writeObject)
|
||||
}
|
||||
// Have to do it like that if i encapsulate the output stream, the cipher could fail saying reuse IV
|
||||
val doFinal = cipher.doFinal(bos1.toByteArray())
|
||||
|
||||
output.write(FORMAT_2.toInt())
|
||||
output.write(salt.size)
|
||||
output.write(salt)
|
||||
output.write(iv.size)
|
||||
output.write(iv)
|
||||
output.write(doFinal)
|
||||
}
|
||||
|
||||
// @RequiresApi(Build.VERSION_CODES.M)
|
||||
// @Throws(IOException::class)
|
||||
// fun saveSecureObjectM(keyAlias: String, file: File, writeObject: Any) {
|
||||
@ -418,15 +348,14 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
@Throws(IOException::class)
|
||||
private fun <T> loadSecureObjectK(keyAlias: String, inputStream: InputStream): T? {
|
||||
private fun <T> loadSecureObject(keyAlias: String, inputStream: InputStream): T? {
|
||||
val (encryptedKey, iv, encrypted) = format1Extract(inputStream)
|
||||
|
||||
// we need to decrypt the key
|
||||
val sKeyBytes = rsaDecrypt(keyAlias, ByteArrayInputStream(encryptedKey))
|
||||
val cipher = Cipher.getInstance(AES_MODE)
|
||||
val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv)
|
||||
val spec = GCMParameterSpec(128, iv)
|
||||
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(sKeyBytes, "AES"), spec)
|
||||
|
||||
val encIS = ByteArrayInputStream(encrypted)
|
||||
@ -440,31 +369,6 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
private fun <T> loadSecureObjectOldNotGood(keyAlias: String, inputStream: InputStream): T? {
|
||||
val (salt, iv, encrypted) = format2Extract(inputStream)
|
||||
|
||||
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||
val tmp = factory.generateSecret(PBEKeySpec(keyAlias.toCharArray(), salt, 10000, 128))
|
||||
val sKey = SecretKeySpec(tmp.encoded, "AES")
|
||||
// we need to decrypt the key
|
||||
|
||||
val cipher = Cipher.getInstance(AES_MODE)
|
||||
val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv)
|
||||
cipher.init(Cipher.DECRYPT_MODE, sKey, spec)
|
||||
|
||||
val encIS = ByteArrayInputStream(encrypted)
|
||||
|
||||
CipherInputStream(encIS, cipher).use {
|
||||
ObjectInputStream(it).use { ois ->
|
||||
val readObject = ois.readObject()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return readObject as? T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
@Throws(Exception::class)
|
||||
private fun rsaEncrypt(alias: String, secret: ByteArray): ByteArray {
|
||||
val privateKeyEntry = getOrGenerateKeyPairForAlias(alias)
|
||||
@ -480,7 +384,6 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||
return outputStream.toByteArray()
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
@Throws(Exception::class)
|
||||
private fun rsaDecrypt(alias: String, encrypted: InputStream): ByteArray {
|
||||
val privateKeyEntry = getOrGenerateKeyPairForAlias(alias)
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.widgets
|
||||
|
||||
import android.os.Build
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.WebView
|
||||
import com.squareup.moshi.Moshi
|
||||
@ -172,11 +171,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
|
||||
val functionLine = "sendResponseFromRiotAndroid('" + eventData["_id"] + "' , " + jsString + ");"
|
||||
Timber.v("BRIDGE sendResponse: $functionLine")
|
||||
// call the javascript method
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
webView?.loadUrl("javascript:$functionLine")
|
||||
} else {
|
||||
webView?.evaluateJavascript(functionLine, null)
|
||||
}
|
||||
webView?.evaluateJavascript(functionLine, null)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## sendResponse() failed ")
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ import android.security.KeyPairGeneratorSpec
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties
|
||||
import android.util.Base64
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.edit
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
@ -48,7 +47,6 @@ import java.security.cert.CertificateException
|
||||
import java.security.spec.AlgorithmParameterSpec
|
||||
import java.security.spec.RSAKeyGenParameterSpec
|
||||
import java.util.Calendar
|
||||
import java.util.zip.GZIPOutputStream
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.CipherInputStream
|
||||
import javax.crypto.CipherOutputStream
|
||||
@ -82,22 +80,6 @@ object CompatUtil {
|
||||
*/
|
||||
private val prng: SecureRandom by lazy(LazyThreadSafetyMode.NONE) { SecureRandom() }
|
||||
|
||||
/**
|
||||
* Create a GZIPOutputStream instance
|
||||
* Special treatment on KitKat device, force the syncFlush param to false
|
||||
* Before Kitkat, this param does not exist and after Kitkat it is set to false by default
|
||||
*
|
||||
* @param outputStream the output stream
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun createGzipOutputStream(outputStream: OutputStream): GZIPOutputStream {
|
||||
return if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
|
||||
GZIPOutputStream(outputStream, false)
|
||||
} else {
|
||||
GZIPOutputStream(outputStream)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AES key used for local storage encryption/decryption with AES/GCM.
|
||||
* The key is created if it does not exist already in the keystore.
|
||||
@ -107,7 +89,6 @@ object CompatUtil {
|
||||
*
|
||||
* @param context the context holding the application shared preferences
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
@Synchronized
|
||||
@Throws(KeyStoreException::class,
|
||||
CertificateException::class,
|
||||
@ -249,10 +230,6 @@ object CompatUtil {
|
||||
KeyStoreException::class,
|
||||
IllegalBlockSizeException::class)
|
||||
fun createCipherOutputStream(out: OutputStream, context: Context): OutputStream? {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
return out
|
||||
}
|
||||
|
||||
val keyAndVersion = getAesGcmLocalProtectionKey(context)
|
||||
|
||||
val cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE)
|
||||
@ -298,10 +275,6 @@ object CompatUtil {
|
||||
InvalidAlgorithmParameterException::class,
|
||||
IOException::class)
|
||||
fun createCipherInputStream(`in`: InputStream, context: Context): InputStream? {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
return `in`
|
||||
}
|
||||
|
||||
val iv_len = `in`.read()
|
||||
if (iv_len != AES_GCM_IV_LENGTH) {
|
||||
Timber.e(TAG, "Invalid IV length $iv_len")
|
||||
|
@ -37,6 +37,7 @@
|
||||
<issue id="SetTextI18n" severity="error" />
|
||||
<issue id="ViewConstructor" severity="error" />
|
||||
<issue id="UseValueOf" severity="error" />
|
||||
<issue id="ObsoleteSdkInt" severity="error" />
|
||||
<issue id="Recycle" severity="error" />
|
||||
<issue id="KotlinPropertyAccess" severity="error" />
|
||||
|
||||
|
@ -22,7 +22,6 @@ import android.content.Context
|
||||
import android.hardware.Camera
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.os.Build
|
||||
import androidx.core.content.getSystemService
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -33,10 +32,6 @@ class HardwareInfo @Inject constructor(
|
||||
* Tell if the device has a back (or external) camera
|
||||
*/
|
||||
fun hasBackCamera(): Boolean {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
return Camera.getNumberOfCameras() > 0
|
||||
}
|
||||
|
||||
val manager = context.getSystemService<CameraManager>() ?: return Camera.getNumberOfCameras() > 0
|
||||
|
||||
return manager.cameraIdList.any {
|
||||
|
@ -20,7 +20,6 @@ import android.content.ClipData
|
||||
import android.content.ClipDescription
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.util.PatternsCompat.WEB_URL
|
||||
|
||||
/**
|
||||
@ -87,13 +86,9 @@ fun analyseIntent(intent: Intent): List<ExternalIntentData> {
|
||||
}
|
||||
}
|
||||
|
||||
var clipData: ClipData? = null
|
||||
val clipData: ClipData? = intent.clipData
|
||||
var mimeTypes: List<String>? = null
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
clipData = intent.clipData
|
||||
}
|
||||
|
||||
// multiple data
|
||||
if (null != clipData) {
|
||||
if (null != clipData.description) {
|
||||
|
@ -19,7 +19,6 @@ package im.vector.app.core.ui.views
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
@ -105,13 +104,7 @@ class BottomSheetActionButton @JvmOverloads constructor(
|
||||
var tint: Int? = null
|
||||
set(value) {
|
||||
field = value
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
leftIconImageView.imageTintList = value?.let { ColorStateList.valueOf(value) }
|
||||
} else {
|
||||
leftIcon?.let {
|
||||
leftIcon = ThemeUtils.tintDrawable(context, it, value ?: ThemeUtils.getColor(context, android.R.attr.textColor))
|
||||
}
|
||||
}
|
||||
leftIconImageView.imageTintList = value?.let { ColorStateList.valueOf(value) }
|
||||
}
|
||||
|
||||
init {
|
||||
|
@ -134,9 +134,7 @@ fun openFileSelection(activity: Activity,
|
||||
allowMultipleSelection: Boolean,
|
||||
requestCode: Int) {
|
||||
val fileIntent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultipleSelection)
|
||||
}
|
||||
fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultipleSelection)
|
||||
|
||||
fileIntent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
fileIntent.type = "*/*"
|
||||
|
@ -101,15 +101,10 @@ fun startNotificationSettingsIntent(activity: AppCompatActivity, requestCode: In
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.packageName)
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
} else {
|
||||
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||
intent.putExtra("app_package", activity.packageName)
|
||||
intent.putExtra("app_uid", activity.applicationInfo?.uid)
|
||||
} else {
|
||||
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
val uri = Uri.fromParts("package", activity.packageName, null)
|
||||
intent.data = uri
|
||||
}
|
||||
activity.startActivityForResult(intent, requestCode)
|
||||
}
|
||||
@ -140,11 +135,7 @@ fun startAddGoogleAccountIntent(context: AppCompatActivity, requestCode: Int) {
|
||||
fun startSharePlainTextIntent(fragment: Fragment, chooserTitle: String?, text: String, subject: String? = null, requestCode: Int? = null) {
|
||||
val share = Intent(Intent.ACTION_SEND)
|
||||
share.type = "text/plain"
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
share.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
|
||||
} else {
|
||||
share.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
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)
|
||||
|
@ -18,10 +18,8 @@ package im.vector.app.features.attachments
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Build
|
||||
import android.util.Pair
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
@ -109,25 +107,19 @@ class AttachmentTypeSelectorView(context: Context,
|
||||
showAtLocation(anchor, Gravity.NO_GRAVITY, 0, anchorCoordinates[1] - contentViewHeight)
|
||||
}
|
||||
contentView.doOnNextLayout {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animateWindowInCircular(anchor, contentView)
|
||||
} else {
|
||||
animateWindowInTranslate(contentView)
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animateButtonIn(galleryButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(cameraButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(fileButton, ANIMATION_DURATION / 4)
|
||||
animateButtonIn(audioButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(contactButton, ANIMATION_DURATION / 4)
|
||||
animateButtonIn(stickersButton, 0)
|
||||
animateWindowInCircular(anchor, contentView)
|
||||
}
|
||||
animateButtonIn(galleryButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(cameraButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(fileButton, ANIMATION_DURATION / 4)
|
||||
animateButtonIn(audioButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(contactButton, ANIMATION_DURATION / 4)
|
||||
animateButtonIn(stickersButton, 0)
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
val capturedAnchor = anchor
|
||||
if (capturedAnchor != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (capturedAnchor != null) {
|
||||
animateWindowOutCircular(capturedAnchor, contentView)
|
||||
} else {
|
||||
animateWindowOutTranslate(contentView)
|
||||
@ -144,7 +136,6 @@ class AttachmentTypeSelectorView(context: Context,
|
||||
button.startAnimation(animation)
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private fun animateWindowInCircular(anchor: View, contentView: View) {
|
||||
val coordinates = getClickCoordinates(anchor, contentView)
|
||||
val animator = ViewAnimationUtils.createCircularReveal(contentView,
|
||||
@ -162,7 +153,6 @@ class AttachmentTypeSelectorView(context: Context,
|
||||
getContentView().startAnimation(animation)
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private fun animateWindowOutCircular(anchor: View, contentView: View) {
|
||||
val coordinates = getClickCoordinates(anchor, contentView)
|
||||
val animator = ViewAnimationUtils.createCircularReveal(getContentView(),
|
||||
|
@ -23,7 +23,6 @@ import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
@ -334,20 +333,6 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
||||
surfaceRenderersAreInitialized = true
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
// for newer version, it will be passed automatically to active media session
|
||||
// in call service
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_HEADSETHOOK -> {
|
||||
callViewModel.handle(VectorCallViewActions.HeadSetButtonPressed)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
private fun handleViewEvents(event: VectorCallViewEvents?) {
|
||||
Timber.v("## VOIP handleViewEvents $event")
|
||||
when (event) {
|
||||
|
@ -18,8 +18,6 @@ package im.vector.app.features.call
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.getSystemService
|
||||
import im.vector.app.ActiveSessionDataSource
|
||||
import im.vector.app.core.services.BluetoothHeadsetReceiver
|
||||
@ -363,11 +361,6 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// Fallback for old android, try to restart capture when attached
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && capturerIsInError && call.mxCall.isVideoCall) {
|
||||
// try to restart capture?
|
||||
videoCapturer?.startCapture(currentCaptureMode.width, currentCaptureMode.height, currentCaptureMode.fps)
|
||||
}
|
||||
// sink existing tracks (configuration change, e.g screen rotation)
|
||||
attachViewRenderersInternal()
|
||||
}
|
||||
@ -478,12 +471,10 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
// We then register in order to restart capture as soon as the camera is available again
|
||||
Timber.v("## VOIP onCameraClosed")
|
||||
this@WebRtcPeerConnectionManager.capturerIsInError = true
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val restarter = CameraRestarter(cameraInUse?.name ?: "", callContext.mxCall.callId)
|
||||
callContext.cameraAvailabilityCallback = restarter
|
||||
val cameraManager = context.getSystemService<CameraManager>()!!
|
||||
cameraManager.registerAvailabilityCallback(restarter, null)
|
||||
}
|
||||
val restarter = CameraRestarter(cameraInUse?.name ?: "", callContext.mxCall.callId)
|
||||
callContext.cameraAvailabilityCallback = restarter
|
||||
val cameraManager = context.getSystemService<CameraManager>()!!
|
||||
cameraManager.registerAvailabilityCallback(restarter, null)
|
||||
}
|
||||
})
|
||||
|
||||
@ -792,10 +783,8 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
currentCall?.localVideoTrack?.setEnabled(false)
|
||||
|
||||
currentCall?.cameraAvailabilityCallback?.let { cameraAvailabilityCallback ->
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val cameraManager = context.getSystemService<CameraManager>()!!
|
||||
cameraManager.unregisterAvailabilityCallback(cameraAvailabilityCallback)
|
||||
}
|
||||
val cameraManager = context.getSystemService<CameraManager>()!!
|
||||
cameraManager.unregisterAvailabilityCallback(cameraAvailabilityCallback)
|
||||
}
|
||||
|
||||
if (originatedByMe) {
|
||||
@ -1041,7 +1030,6 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
inner class CameraRestarter(val cameraId: String, val callId: String) : CameraManager.AvailabilityCallback() {
|
||||
|
||||
override fun onCameraAvailable(cameraId: String) {
|
||||
|
@ -82,9 +82,7 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
configuration.locale = locale
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
configuration.setLayoutDirection(locale)
|
||||
}
|
||||
configuration.setLayoutDirection(locale)
|
||||
@Suppress("DEPRECATION")
|
||||
resources.updateConfiguration(configuration, resources.displayMetrics)
|
||||
return context
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package im.vector.app.features.login
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
@ -48,9 +47,7 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
|
||||
}
|
||||
sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
|
@ -22,7 +22,6 @@ import android.annotation.SuppressLint
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Bitmap
|
||||
import android.net.http.SslError
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
@ -102,14 +101,6 @@ class LoginWebFragment @Inject constructor(
|
||||
launchWebView(state)
|
||||
} else {
|
||||
if (!cookieManager.hasCookies()) {
|
||||
launchWebView(state)
|
||||
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
try {
|
||||
cookieManager.removeAllCookie()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, " cookieManager.removeAllCookie() fails")
|
||||
}
|
||||
|
||||
launchWebView(state)
|
||||
} else {
|
||||
try {
|
||||
|
@ -19,12 +19,10 @@ package im.vector.app.features.media
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.transition.addListener
|
||||
@ -84,7 +82,7 @@ class ImageMediaViewerActivity : VectorBaseActivity() {
|
||||
|
||||
configureToolbar(imageMediaViewerToolbar, mediaData)
|
||||
|
||||
if (isFirstCreation() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && addTransitionListener()) {
|
||||
if (isFirstCreation() && addTransitionListener()) {
|
||||
// Encrypted image
|
||||
imageTransitionView.isVisible = true
|
||||
imageMediaViewerImageView.isVisible = false
|
||||
@ -183,7 +181,6 @@ class ImageMediaViewerActivity : VectorBaseActivity() {
|
||||
*
|
||||
* @return true if we were successful in adding a listener to the enter transition
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private fun addTransitionListener(): Boolean {
|
||||
val transition = window.sharedElementEnterTransition
|
||||
|
||||
|
@ -20,6 +20,7 @@ import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.os.Trace
|
||||
import android.text.StaticLayout
|
||||
import android.text.TextPaint
|
||||
import android.util.AttributeSet
|
||||
@ -43,7 +44,7 @@ class EmojiDrawView @JvmOverloads constructor(
|
||||
var emoji: String? = null
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
EmojiRecyclerAdapter.beginTraceSession("EmojiDrawView.onDraw")
|
||||
Trace.beginSection("EmojiDrawView.onDraw")
|
||||
super.onDraw(canvas)
|
||||
canvas?.save()
|
||||
val space = abs((width - emojiSize) / 2f)
|
||||
@ -52,7 +53,7 @@ class EmojiDrawView @JvmOverloads constructor(
|
||||
mLayout!!.draw(canvas)
|
||||
}
|
||||
canvas?.restore()
|
||||
EmojiRecyclerAdapter.endTraceSession()
|
||||
Trace.endSection()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -125,7 +125,7 @@ class EmojiRecyclerAdapter @Inject constructor(
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
beginTraceSession("MyAdapter.onCreateViewHolder")
|
||||
Trace.beginSection("MyAdapter.onCreateViewHolder")
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val itemView = inflater.inflate(viewType, parent, false)
|
||||
itemView.setOnClickListener(itemClickListener)
|
||||
@ -133,16 +133,16 @@ class EmojiRecyclerAdapter @Inject constructor(
|
||||
R.layout.grid_section_header -> SectionViewHolder(itemView)
|
||||
else -> EmojiViewHolder(itemView)
|
||||
}
|
||||
endTraceSession()
|
||||
Trace.endSection()
|
||||
return viewHolder
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
beginTraceSession("MyAdapter.getItemViewType")
|
||||
Trace.beginSection("MyAdapter.getItemViewType")
|
||||
if (isSection(position)) {
|
||||
return R.layout.grid_section_header
|
||||
}
|
||||
endTraceSession()
|
||||
Trace.endSection()
|
||||
return R.layout.grid_item_emoji
|
||||
}
|
||||
|
||||
@ -183,7 +183,7 @@ class EmojiRecyclerAdapter @Inject constructor(
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
beginTraceSession("MyAdapter.onBindViewHolder")
|
||||
Trace.beginSection("MyAdapter.onBindViewHolder")
|
||||
val sectionNumber = getSectionForAbsoluteIndex(position)
|
||||
if (isSection(position)) {
|
||||
holder.bind(dataSource.rawData.categories[sectionNumber].name)
|
||||
@ -202,7 +202,7 @@ class EmojiRecyclerAdapter @Inject constructor(
|
||||
holder.bind(null)
|
||||
}
|
||||
}
|
||||
endTraceSession()
|
||||
Trace.endSection()
|
||||
}
|
||||
|
||||
override fun onViewRecycled(holder: ViewHolder) {
|
||||
@ -259,18 +259,6 @@ class EmojiRecyclerAdapter @Inject constructor(
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun endTraceSession() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
Trace.endSection()
|
||||
}
|
||||
}
|
||||
|
||||
fun beginTraceSession(sectionName: String) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
Trace.beginSection(sectionName)
|
||||
}
|
||||
}
|
||||
|
||||
private val staticLayoutCache = HashMap<String, StaticLayout>()
|
||||
|
||||
private fun getStaticLayoutForEmoji(emoji: String): StaticLayout {
|
||||
|
@ -18,7 +18,6 @@ package im.vector.app.features.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import im.vector.app.BuildConfig
|
||||
@ -108,13 +107,11 @@ object VectorLocale {
|
||||
putString(APPLICATION_LOCALE_VARIANT_KEY, variant)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val script = locale.script
|
||||
if (script.isEmpty()) {
|
||||
remove(APPLICATION_LOCALE_SCRIPT_KEY)
|
||||
} else {
|
||||
putString(APPLICATION_LOCALE_SCRIPT_KEY, script)
|
||||
}
|
||||
val script = locale.script
|
||||
if (script.isEmpty()) {
|
||||
remove(APPLICATION_LOCALE_SCRIPT_KEY)
|
||||
} else {
|
||||
putString(APPLICATION_LOCALE_SCRIPT_KEY, script)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,40 +125,15 @@ object VectorLocale {
|
||||
* @return the localized string
|
||||
*/
|
||||
private fun getString(context: Context, locale: Locale, resourceId: Int): String {
|
||||
val result: String
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
val config = Configuration(context.resources.configuration)
|
||||
config.setLocale(locale)
|
||||
result = try {
|
||||
context.createConfigurationContext(config).getText(resourceId).toString()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## getString() failed")
|
||||
// use the default one
|
||||
context.getString(resourceId)
|
||||
}
|
||||
} else {
|
||||
val resources = context.resources
|
||||
val conf = resources.configuration
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val savedLocale = conf.locale
|
||||
@Suppress("DEPRECATION")
|
||||
conf.locale = locale
|
||||
@Suppress("DEPRECATION")
|
||||
resources.updateConfiguration(conf, null)
|
||||
|
||||
// retrieve resources from desired locale
|
||||
result = resources.getString(resourceId)
|
||||
|
||||
// restore original locale
|
||||
@Suppress("DEPRECATION")
|
||||
conf.locale = savedLocale
|
||||
@Suppress("DEPRECATION")
|
||||
resources.updateConfiguration(conf, null)
|
||||
val config = Configuration(context.resources.configuration)
|
||||
config.setLocale(locale)
|
||||
return try {
|
||||
context.createConfigurationContext(config).getText(resourceId).toString()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## getString() failed")
|
||||
// use the default one
|
||||
context.getString(resourceId)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
@ -194,22 +166,18 @@ object VectorLocale {
|
||||
}
|
||||
|
||||
val list = knownLocalesSet.mapNotNull { (language, country, script) ->
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
try {
|
||||
Locale.Builder()
|
||||
.setLanguage(language)
|
||||
.setRegion(country)
|
||||
.setScript(script)
|
||||
.build()
|
||||
} catch (exception: IllformedLocaleException) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
throw exception
|
||||
}
|
||||
// Ignore this locale in production
|
||||
null
|
||||
try {
|
||||
Locale.Builder()
|
||||
.setLanguage(language)
|
||||
.setRegion(country)
|
||||
.setScript(script)
|
||||
.build()
|
||||
} catch (exception: IllformedLocaleException) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
throw exception
|
||||
}
|
||||
} else {
|
||||
Locale(language, country)
|
||||
// Ignore this locale in production
|
||||
null
|
||||
}
|
||||
}
|
||||
// sort by human display names
|
||||
@ -229,9 +197,7 @@ object VectorLocale {
|
||||
return buildString {
|
||||
append(locale.getDisplayLanguage(locale))
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||
&& locale.script != ISO_15924_LATN
|
||||
&& locale.getDisplayScript(locale).isNotEmpty()) {
|
||||
if (locale.script != ISO_15924_LATN && locale.getDisplayScript(locale).isNotEmpty()) {
|
||||
append(" - ")
|
||||
append(locale.getDisplayScript(locale))
|
||||
}
|
||||
@ -254,7 +220,7 @@ object VectorLocale {
|
||||
return buildString {
|
||||
append("[")
|
||||
append(locale.displayLanguage)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && locale.script != ISO_15924_LATN) {
|
||||
if (locale.script != ISO_15924_LATN) {
|
||||
append(" - ")
|
||||
append(locale.displayScript)
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package im.vector.app.features.settings.troubleshoot
|
||||
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -87,9 +86,7 @@ class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList<Troublesh
|
||||
statusIconImage.visibility = View.VISIBLE
|
||||
statusIconImage.setImageResource(R.drawable.unit_test_ko)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
statusIconImage.imageTintList = null
|
||||
}
|
||||
statusIconImage.imageTintList = null
|
||||
|
||||
descriptionText.setTextColor(ContextCompat.getColor(context, R.color.riotx_notice))
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ package im.vector.app.features.webview
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebView
|
||||
import androidx.annotation.CallSuper
|
||||
@ -70,10 +69,8 @@ class VectorWebViewActivity : VectorBaseActivity() {
|
||||
displayZoomControls = false
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val cookieManager = android.webkit.CookieManager.getInstance()
|
||||
cookieManager.setAcceptThirdPartyCookies(simple_webview, true)
|
||||
}
|
||||
val cookieManager = android.webkit.CookieManager.getInstance()
|
||||
cookieManager.setAcceptThirdPartyCookies(simple_webview, true)
|
||||
|
||||
val url = intent.extras?.getString(EXTRA_URL)
|
||||
val title = intent.extras?.getString(EXTRA_TITLE, USE_TITLE_FROM_WEB_PAGE)
|
||||
|
@ -26,7 +26,6 @@ import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebResourceResponse
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.annotation.RequiresApi
|
||||
|
||||
/**
|
||||
* This class inherits from WebViewClient. It has to be used with a WebView.
|
||||
@ -58,7 +57,6 @@ class VectorWebViewClient(private val eventListener: WebViewEventListener) : Web
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
override fun onReceivedHttpError(view: WebView, request: WebResourceRequest, errorResponse: WebResourceResponse) {
|
||||
super.onReceivedHttpError(view, request, errorResponse)
|
||||
eventListener.onHttpError(request.url.toString(),
|
||||
|
@ -16,7 +16,6 @@
|
||||
package im.vector.app.features.widgets.permissions
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Build
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.style.BulletSpan
|
||||
@ -71,18 +70,7 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
permissionData.permissionsList.forEach {
|
||||
infoBuilder.append("\n")
|
||||
val bulletPoint = getString(it)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
infoBuilder.append(bulletPoint, BulletSpan(resources.getDimension(R.dimen.quote_gap).toInt()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
} else {
|
||||
val start = infoBuilder.length
|
||||
infoBuilder.append(bulletPoint)
|
||||
infoBuilder.setSpan(
|
||||
BulletSpan(resources.getDimension(R.dimen.quote_gap).toInt()),
|
||||
start,
|
||||
bulletPoint.length,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
}
|
||||
infoBuilder.append(bulletPoint, BulletSpan(resources.getDimension(R.dimen.quote_gap).toInt()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
infoBuilder.append("\n")
|
||||
widgetPermissionSharedInfo.text = infoBuilder
|
||||
|
@ -17,7 +17,6 @@
|
||||
package im.vector.app.features.widgets.webview
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.PermissionRequest
|
||||
@ -68,10 +67,8 @@ fun WebView.setupForWidget(webViewEventListener: WebViewEventListener) {
|
||||
}
|
||||
webViewClient = VectorWebViewClient(webViewEventListener)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val cookieManager = CookieManager.getInstance()
|
||||
cookieManager.setAcceptThirdPartyCookies(this, false)
|
||||
}
|
||||
val cookieManager = CookieManager.getInstance()
|
||||
cookieManager.setAcceptThirdPartyCookies(this, false)
|
||||
}
|
||||
|
||||
fun WebView.clearAfterWidget() {
|
||||
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- End and Start attribute has to be set here -->
|
||||
|
||||
</resources>
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<dimen name="floating_action_button_margin">16dp</dimen>
|
||||
|
||||
<!-- Improve size (+20dp) to take status bar height into account -->
|
||||
<dimen name="navigation_view_height">196dp</dimen>
|
||||
<dimen name="navigation_avatar_top_margin">44dp</dimen>
|
||||
|
||||
</resources>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
|
||||
</resources>
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Black.v21" parent="AppTheme.Base.Black">
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_black</item>
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_black</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
|
||||
<!-- specify shared element enter and exit transitions -->
|
||||
<item name="android:windowSharedElementEnterTransition">@transition/image_preview_transition</item>
|
||||
<item name="android:windowSharedElementExitTransition">@transition/image_preview_transition</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Black" parent="AppTheme.Black.v21" />
|
||||
|
||||
</resources>
|
@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Launcher.v21" parent="AppTheme.Launcher.Base">
|
||||
<item name="android:statusBarColor">@color/riotx_accent</item>
|
||||
<item name="android:navigationBarColor">@color/riotx_accent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Launcher" parent="AppTheme.Launcher.v21"/>
|
||||
|
||||
<style name="AppTheme.AttachmentsPreview" parent="AppTheme.Base.Black">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Dark.v21" parent="AppTheme.Base.Dark">
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
|
||||
<!-- specify shared element enter and exit transitions -->
|
||||
<item name="android:windowSharedElementEnterTransition">@transition/image_preview_transition</item>
|
||||
<item name="android:windowSharedElementExitTransition">@transition/image_preview_transition</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dark" parent="AppTheme.Dark.v21" />
|
||||
|
||||
</resources>
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Light.v21" parent="AppTheme.Base.Light">
|
||||
<!-- Use dark color, to have enough contrast with icons color. windowLightStatusBar is only available in API 23+ -->
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
<!-- Use dark color, to have enough contrast with icons color. windowLightNavigationBar is only available in API 27+ -->
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
|
||||
<!-- specify shared element enter and exit transitions -->
|
||||
<item name="android:windowSharedElementEnterTransition">@transition/image_preview_transition</item>
|
||||
<item name="android:windowSharedElementExitTransition">@transition/image_preview_transition</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Light" parent="AppTheme.Light.v21"/>
|
||||
|
||||
</resources>
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Status.v21" parent="AppTheme.Base.Status">
|
||||
<!-- Use dark color, to have enough contrast with icons color. windowLightStatusBar is only available in API 23+ -->
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
<!-- Use dark color, to have enough contrast with icons color. windowLightNavigationBar is only available in API 27+ -->
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
|
||||
<!-- specify shared element enter and exit transitions -->
|
||||
<item name="android:windowSharedElementEnterTransition">@transition/image_preview_transition</item>
|
||||
<item name="android:windowSharedElementExitTransition">@transition/image_preview_transition</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Status" parent="AppTheme.Status.v21" />
|
||||
|
||||
</resources>
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Black.v23" parent="AppTheme.Black.v21">
|
||||
<style name="AppTheme.Black.v23" parent="AppTheme.Base.Black">
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
</style>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Dark.v23" parent="AppTheme.Dark.v21">
|
||||
<style name="AppTheme.Dark.v23" parent="AppTheme.Base.Dark">
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
</style>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Light.v23" parent="AppTheme.Light.v21">
|
||||
<style name="AppTheme.Light.v23" parent="AppTheme.Base.Light">
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_light</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
</style>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Status.v23" parent="AppTheme.Status.v21">
|
||||
<style name="AppTheme.Status.v23" parent="AppTheme.Base.Status">
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_light</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
</style>
|
||||
|
@ -9,9 +9,9 @@
|
||||
<dimen name="layout_vertical_margin_big">32dp</dimen>
|
||||
|
||||
<dimen name="profile_avatar_size">50dp</dimen>
|
||||
<dimen name="floating_action_button_margin">0dp</dimen>
|
||||
<dimen name="navigation_view_height">172dp</dimen>
|
||||
<dimen name="navigation_avatar_top_margin">20dp</dimen>
|
||||
<dimen name="floating_action_button_margin">16dp</dimen>
|
||||
<dimen name="navigation_view_height">196dp</dimen>
|
||||
<dimen name="navigation_avatar_top_margin">44dp</dimen>
|
||||
<dimen name="item_decoration_left_margin">72dp</dimen>
|
||||
|
||||
<dimen name="chat_avatar_size">40dp</dimen>
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- On post Lollipop use default background drawable instead of color -->
|
||||
<style name="Vector.PopupMenu" parent="Vector.PopupMenuBase" />
|
||||
|
||||
</resources>
|
@ -63,14 +63,6 @@
|
||||
<item name="android:dropDownVerticalOffset">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Vector.PopupMenu" parent="Vector.PopupMenuBase">
|
||||
<!--
|
||||
Before Lollipop the popup background is white on dark theme, so force color here.
|
||||
(v21 will revert back to default drawable)
|
||||
-->
|
||||
<item name="android:popupBackground">?colorBackgroundFloating</item>
|
||||
</style>
|
||||
|
||||
<!-- actionbar icons color -->
|
||||
<style name="Vector.ActionBarTheme" parent="ThemeOverlay.MaterialComponents.ActionBar">
|
||||
<item name="colorControlNormal">@android:color/white</item>
|
||||
|
@ -81,6 +81,15 @@
|
||||
<item name="riotx_bottom_nav_background_color">@color/riotx_bottom_nav_background_color_black</item>
|
||||
<item name="riotx_bottom_nav_background_border_color">@color/riotx_bottom_nav_background_border_color_black</item>
|
||||
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_black</item>
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_black</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
|
||||
<!-- specify shared element enter and exit transitions -->
|
||||
<item name="android:windowSharedElementEnterTransition">@transition/image_preview_transition</item>
|
||||
<item name="android:windowSharedElementExitTransition">@transition/image_preview_transition</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Black" parent="AppTheme.Base.Black" />
|
||||
|
@ -6,11 +6,16 @@
|
||||
|
||||
<style name="AppTheme.Launcher.Base" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/splash</item>
|
||||
<item name="android:statusBarColor">@color/riotx_accent</item>
|
||||
<item name="android:navigationBarColor">@color/riotx_accent</item>
|
||||
|
||||
<item name="colorPrimaryDark">@color/primary_color_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AttachmentsPreview" parent="AppTheme.Base.Black"/>
|
||||
<style name="AppTheme.AttachmentsPreview" parent="AppTheme.Base.Black">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Transparent" parent="AppTheme.Base.Black">
|
||||
<item name="windowActionBar">false</item>
|
||||
|
@ -182,6 +182,15 @@
|
||||
<item name="pf_fingerprint_button">@style/PinCodeFingerprintButtonStyle</item>
|
||||
<item name="pf_next">@style/PinCodeNextButtonStyle</item>
|
||||
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
|
||||
<!-- specify shared element enter and exit transitions -->
|
||||
<item name="android:windowSharedElementEnterTransition">@transition/image_preview_transition</item>
|
||||
<item name="android:windowSharedElementExitTransition">@transition/image_preview_transition</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dark" parent="AppTheme.Base.Dark" />
|
||||
|
@ -182,6 +182,17 @@
|
||||
<item name="pf_fingerprint_button">@style/PinCodeFingerprintButtonStyle</item>
|
||||
<item name="pf_next">@style/PinCodeNextButtonStyle</item>
|
||||
|
||||
<!-- Use dark color, to have enough contrast with icons color. windowLightStatusBar is only available in API 23+ -->
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
<!-- Use dark color, to have enough contrast with icons color. windowLightNavigationBar is only available in API 27+ -->
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
|
||||
<!-- specify shared element enter and exit transitions -->
|
||||
<item name="android:windowSharedElementEnterTransition">@transition/image_preview_transition</item>
|
||||
<item name="android:windowSharedElementExitTransition">@transition/image_preview_transition</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Light" parent="AppTheme.Base.Light" />
|
||||
|
@ -99,6 +99,18 @@
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
||||
<item name="bottomSheetDialogTheme">@style/Vector.BottomSheet.Status</item>
|
||||
|
||||
<!-- Use dark color, to have enough contrast with icons color. windowLightStatusBar is only available in API 23+ -->
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
<!-- Use dark color, to have enough contrast with icons color. windowLightNavigationBar is only available in API 27+ -->
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_dark</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
|
||||
<!-- specify shared element enter and exit transitions -->
|
||||
<item name="android:windowSharedElementEnterTransition">@transition/image_preview_transition</item>
|
||||
<item name="android:windowSharedElementExitTransition">@transition/image_preview_transition</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Status" parent="AppTheme.Base.Status" />
|
||||
|
Loading…
Reference in New Issue
Block a user