Set minSdkVersion to 23 (Android 6)

Signed-off-by: Tim Krüger <t@timkrueger.me>
This commit is contained in:
Tim Krüger 2022-10-14 11:52:17 +02:00
parent 49da463971
commit 4b46270362
No known key found for this signature in database
GPG Key ID: FECE3A7222C52A4E
17 changed files with 87 additions and 257 deletions

View File

@ -42,7 +42,7 @@ android {
namespace 'com.nextcloud.talk' namespace 'com.nextcloud.talk'
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 23
targetSdkVersion 31 targetSdkVersion 31
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@ -22,7 +22,6 @@ package com.nextcloud.talk.activities
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.WindowManager import android.view.WindowManager
@ -76,9 +75,7 @@ open class BaseActivity : AppCompatActivity() {
} }
if (appPreferences.isScreenLocked) { if (appPreferences.isScreenLocked) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { SecurityUtils.createKey(appPreferences.screenLockTimeout)
SecurityUtils.createKey(appPreferences.screenLockTimeout)
}
} }
} }

View File

@ -732,10 +732,8 @@ public class CallActivity extends CallBaseActivity {
} else { } else {
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CALL)) { if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CALL)) {
onPermissionsGranted(); onPermissionsGranted();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(PERMISSIONS_CALL, 100);
} else { } else {
onRequestPermissionsResult(100, PERMISSIONS_CALL, new int[]{1, 1}); requestPermissions(PERMISSIONS_CALL, 100);
} }
} }
@ -980,11 +978,7 @@ public class CallActivity extends CallBaseActivity {
R.string.nc_microphone_permission_permanently_denied, R.string.nc_microphone_permission_permanently_denied,
R.string.nc_permissions_settings, (AppCompatActivity) this); R.string.nc_permissions_settings, (AppCompatActivity) this);
} else { } else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(PERMISSIONS_MICROPHONE, 100);
requestPermissions(PERMISSIONS_MICROPHONE, 100);
} else {
onRequestPermissionsResult(100, PERMISSIONS_MICROPHONE, new int[]{1});
}
} }
} }
@ -1017,12 +1011,7 @@ public class CallActivity extends CallBaseActivity {
R.string.nc_camera_permission_permanently_denied, R.string.nc_camera_permission_permanently_denied,
R.string.nc_permissions_settings, (AppCompatActivity) this); R.string.nc_permissions_settings, (AppCompatActivity) this);
} else { } else {
requestPermissions(PERMISSIONS_CAMERA, 100);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(PERMISSIONS_CAMERA, 100);
} else {
onRequestPermissionsResult(100, PERMISSIONS_CAMERA, new int[]{1});
}
} }
} }

View File

@ -24,12 +24,10 @@ package com.nextcloud.talk.activities
import android.app.KeyguardManager import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.ContactsContract import android.provider.ContactsContract
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi
import autodagger.AutoInjector import autodagger.AutoInjector
import com.bluelinelabs.conductor.Conductor import com.bluelinelabs.conductor.Conductor
import com.bluelinelabs.conductor.Router import com.bluelinelabs.conductor.Router
@ -148,10 +146,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
super.onStart() super.onStart()
Log.d(TAG, "onStart: Activity: " + System.identityHashCode(this).toString()) Log.d(TAG, "onStart: Activity: " + System.identityHashCode(this).toString())
logRouterBackStack(router!!) logRouterBackStack(router!!)
lockScreenIfConditionsApply()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
lockScreenIfConditionsApply()
}
} }
override fun onResume() { override fun onResume() {
@ -323,7 +318,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
}) })
} }
@RequiresApi(api = Build.VERSION_CODES.M)
fun lockScreenIfConditionsApply() { fun lockScreenIfConditionsApply() {
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) { if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {

View File

@ -64,7 +64,6 @@ import com.nextcloud.talk.jobs.SignalingSettingsWorker
import com.nextcloud.talk.ui.theme.ThemeModule import com.nextcloud.talk.ui.theme.ThemeModule
import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.DeviceUtils import com.nextcloud.talk.utils.DeviceUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageModule import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageModule
import com.nextcloud.talk.utils.database.user.UserModule import com.nextcloud.talk.utils.database.user.UserModule
@ -163,7 +162,6 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
securityKeyManager.init(this, securityKeyConfig) securityKeyManager.init(this, securityKeyConfig)
initializeWebRtc() initializeWebRtc()
DisplayUtils.useCompatVectorIfNeeded()
buildComponent() buildComponent()
DavUtils.registerCustomFactories() DavUtils.registerCustomFactories()

View File

@ -1149,14 +1149,10 @@ class ChatController(args: Bundle) :
} }
private fun isRecordAudioPermissionGranted(): Boolean { private fun isRecordAudioPermissionGranted(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return PermissionChecker.checkSelfPermission(
return PermissionChecker.checkSelfPermission( context,
context, Manifest.permission.RECORD_AUDIO
Manifest.permission.RECORD_AUDIO ) == PermissionChecker.PERMISSION_GRANTED
) == PermissionChecker.PERMISSION_GRANTED
} else {
true
}
} }
private fun startAudioRecording(file: String) { private fun startAudioRecording(file: String) {

View File

@ -442,23 +442,19 @@ class LocationPickerController(args: Bundle) :
private fun isLocationPermissionsGranted(): Boolean { private fun isLocationPermissionsGranted(): Boolean {
fun isCoarseLocationGranted(): Boolean { fun isCoarseLocationGranted(): Boolean {
return PermissionChecker.checkSelfPermission( return PermissionChecker.checkSelfPermission(
context!!, context,
Manifest.permission.ACCESS_COARSE_LOCATION Manifest.permission.ACCESS_COARSE_LOCATION
) == PermissionChecker.PERMISSION_GRANTED ) == PermissionChecker.PERMISSION_GRANTED
} }
fun isFineLocationGranted(): Boolean { fun isFineLocationGranted(): Boolean {
return PermissionChecker.checkSelfPermission( return PermissionChecker.checkSelfPermission(
context!!, context,
Manifest.permission.ACCESS_FINE_LOCATION Manifest.permission.ACCESS_FINE_LOCATION
) == PermissionChecker.PERMISSION_GRANTED ) == PermissionChecker.PERMISSION_GRANTED
} }
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return isCoarseLocationGranted() && isFineLocationGranted()
isCoarseLocationGranted() && isFineLocationGranted()
} else {
true
}
} }
private fun requestLocationPermissions() { private fun requestLocationPermissions() {

View File

@ -25,12 +25,10 @@ import android.app.Activity
import android.app.KeyguardManager import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import androidx.annotation.RequiresApi
import androidx.biometric.BiometricPrompt import androidx.biometric.BiometricPrompt
import androidx.biometric.BiometricPrompt.PromptInfo import androidx.biometric.BiometricPrompt.PromptInfo
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
@ -62,15 +60,11 @@ class LockedController : BaseController(R.layout.controller_locked) {
override fun onViewBound(view: View) { override fun onViewBound(view: View) {
super.onViewBound(view) super.onViewBound(view)
sharedApplication!!.componentApplication.inject(this) sharedApplication!!.componentApplication.inject(this)
binding.unlockContainer.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { unlock()
binding.unlockContainer.setOnClickListener {
unlock()
}
} }
} }
@RequiresApi(api = Build.VERSION_CODES.M)
override fun onAttach(view: View) { override fun onAttach(view: View) {
super.onAttach(view) super.onAttach(view)
Log.d(TAG, "onAttach") Log.d(TAG, "onAttach")
@ -92,12 +86,10 @@ class LockedController : BaseController(R.layout.controller_locked) {
Log.d(TAG, "onDetach") Log.d(TAG, "onDetach")
} }
@RequiresApi(api = Build.VERSION_CODES.M)
fun unlock() { fun unlock() {
checkIfWeAreSecure() checkIfWeAreSecure()
} }
@RequiresApi(api = Build.VERSION_CODES.M)
private fun showBiometricDialog() { private fun showBiometricDialog() {
val context: Context? = activity val context: Context? = activity
if (context != null) { if (context != null) {
@ -140,11 +132,10 @@ class LockedController : BaseController(R.layout.controller_locked) {
} }
} }
@RequiresApi(api = Build.VERSION_CODES.M)
private fun checkIfWeAreSecure() { private fun checkIfWeAreSecure() {
val keyguardManager = activity?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager? val keyguardManager = activity?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
if (keyguardManager?.isKeyguardSecure == true && appPreferences!!.isScreenLocked) { if (keyguardManager?.isKeyguardSecure == true && appPreferences.isScreenLocked) {
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences!!.screenLockTimeout)) { if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
Log.d(TAG, "showBiometricDialog because 'we are NOT authenticated'...") Log.d(TAG, "showBiometricDialog because 'we are NOT authenticated'...")
showBiometricDialog() showBiometricDialog()
} else { } else {
@ -172,8 +163,7 @@ class LockedController : BaseController(R.layout.controller_locked) {
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) { if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
if ( if (
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)
SecurityUtils.checkIfWeAreAuthenticated(appPreferences!!.screenLockTimeout)
) { ) {
Log.d(TAG, "All went well, dismiss locked controller") Log.d(TAG, "All went well, dismiss locked controller")
router.popCurrentController() router.popCurrentController()

View File

@ -157,18 +157,13 @@ class SettingsController : BaseController(R.layout.controller_settings) {
binding.settingsIncognitoKeyboard.visibility = View.GONE binding.settingsIncognitoKeyboard.visibility = View.GONE
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { binding.settingsScreenLock.setSummary(
binding.settingsScreenLock.visibility = View.GONE String.format(
binding.settingsScreenLockTimeout.visibility = View.GONE Locale.getDefault(),
} else { resources!!.getString(R.string.nc_settings_screen_lock_desc),
binding.settingsScreenLock.setSummary( resources!!.getString(R.string.nc_app_product_name)
String.format(
Locale.getDefault(),
resources!!.getString(R.string.nc_settings_screen_lock_desc),
resources!!.getString(R.string.nc_app_product_name)
)
) )
} )
setupPrivacyUrl() setupPrivacyUrl()
setupSourceCodeUrl() setupSourceCodeUrl()
@ -662,10 +657,8 @@ class SettingsController : BaseController(R.layout.controller_settings) {
appPreferences.isKeyboardIncognito appPreferences.isKeyboardIncognito
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { (binding.settingsIncognitoKeyboard.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding.settingsIncognitoKeyboard.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked = appPreferences.isKeyboardIncognito
appPreferences.isKeyboardIncognito
}
if (CapabilitiesUtilNew.isReadStatusAvailable(userManager.currentUser.blockingGet())) { if (CapabilitiesUtilNew.isReadStatusAvailable(userManager.currentUser.blockingGet())) {
(binding.settingsReadPrivacy.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked = (binding.settingsReadPrivacy.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
@ -679,29 +672,27 @@ class SettingsController : BaseController(R.layout.controller_settings) {
} }
private fun setupScreenLockSetting() { private fun setupScreenLockSetting() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager if (keyguardManager.isKeyguardSecure) {
if (keyguardManager.isKeyguardSecure) { binding.settingsScreenLock.isEnabled = true
binding.settingsScreenLock.isEnabled = true binding.settingsScreenLockTimeout.isEnabled = true
binding.settingsScreenLockTimeout.isEnabled = true (binding.settingsScreenLock.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding.settingsScreenLock.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked = appPreferences.isScreenLocked
appPreferences.isScreenLocked binding.settingsScreenLockTimeout.isEnabled = appPreferences.isScreenLocked
binding.settingsScreenLockTimeout.isEnabled = appPreferences.isScreenLocked if (appPreferences.isScreenLocked) {
if (appPreferences.isScreenLocked) { binding.settingsScreenLockTimeout.alpha = ENABLED_ALPHA
binding.settingsScreenLockTimeout.alpha = ENABLED_ALPHA
} else {
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
}
binding.settingsScreenLock.alpha = ENABLED_ALPHA
} else { } else {
binding.settingsScreenLock.isEnabled = false
binding.settingsScreenLockTimeout.isEnabled = false
appPreferences.removeScreenLock()
appPreferences.removeScreenLockTimeout()
(binding.settingsScreenLock.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked = false
binding.settingsScreenLock.alpha = DISABLED_ALPHA
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
} }
binding.settingsScreenLock.alpha = ENABLED_ALPHA
} else {
binding.settingsScreenLock.isEnabled = false
binding.settingsScreenLockTimeout.isEnabled = false
appPreferences.removeScreenLock()
appPreferences.removeScreenLockTimeout()
(binding.settingsScreenLock.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked = false
binding.settingsScreenLock.alpha = DISABLED_ALPHA
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
} }
} }
@ -805,9 +796,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
private inner class ScreenLockTimeoutListener : OnPreferenceValueChangedListener<String?> { private inner class ScreenLockTimeoutListener : OnPreferenceValueChangedListener<String?> {
override fun onChanged(newValue: String?) { override fun onChanged(newValue: String?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { SecurityUtils.createKey(appPreferences.screenLockTimeout)
SecurityUtils.createKey(appPreferences.screenLockTimeout)
}
} }
} }

View File

@ -447,11 +447,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
EmojiCompat.get().process(pushMessage.text!!) EmojiCompat.get().process(pushMessage.text!!)
) )
} }
if (Build.VERSION.SDK_INT >= 23) {
// This method should exist since API 21, but some phones don't have it notificationBuilder.color = context!!.resources.getColor(R.color.colorPrimary)
// So as a safeguard, we don't use it until 23
notificationBuilder.color = context!!.resources.getColor(R.color.colorPrimary)
}
val notificationInfoBundle = Bundle() val notificationInfoBundle = Bundle()
notificationInfoBundle.putLong(KEY_INTERNAL_USER_ID, signatureVerification.user!!.id!!) notificationInfoBundle.putLong(KEY_INTERNAL_USER_ID, signatureVerification.user!!.id!!)
// could be an ID or a TOKEN // could be an ID or a TOKEN
@ -694,7 +692,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
.subscribe(object : Observer<ParticipantsOverall> { .subscribe(object : Observer<ParticipantsOverall> {
override fun onSubscribe(d: Disposable) = Unit override fun onSubscribe(d: Disposable) = Unit
@RequiresApi(Build.VERSION_CODES.M)
override fun onNext(participantsOverall: ParticipantsOverall) { override fun onNext(participantsOverall: ParticipantsOverall) {
val participantList: List<Participant> = participantsOverall.ocs!!.data!! val participantList: List<Participant> = participantsOverall.ocs!!.data!!
hasParticipantsInCall = participantList.isNotEmpty() hasParticipantsInCall = participantList.isNotEmpty()
@ -726,7 +723,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
Log.e(TAG, "Error in getPeersForCall", e) Log.e(TAG, "Error in getPeersForCall", e)
} }
@RequiresApi(Build.VERSION_CODES.M)
override fun onComplete() { override fun onComplete() {
if (isCallNotificationVisible) { if (isCallNotificationVisible) {
@ -821,7 +817,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
return PendingIntent.getActivity(context, requestCode, intent, intentFlag) return PendingIntent.getActivity(context, requestCode, intent, intentFlag)
} }
@RequiresApi(Build.VERSION_CODES.M)
private fun isCallNotificationVisible(decryptedPushMessage: DecryptedPushMessage): Boolean { private fun isCallNotificationVisible(decryptedPushMessage: DecryptedPushMessage): Boolean {
var isVisible = false var isVisible = false

View File

@ -295,7 +295,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
false false
} }
} }
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> { else -> {
if (PermissionChecker.checkSelfPermission( if (PermissionChecker.checkSelfPermission(
context, context,
Manifest.permission.WRITE_EXTERNAL_STORAGE Manifest.permission.WRITE_EXTERNAL_STORAGE
@ -308,10 +308,6 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
false false
} }
} }
else -> { // permission is automatically granted on sdk<23 upon installation
Log.d(TAG, "Permission is granted")
true
}
} }
} }
@ -325,7 +321,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
REQUEST_PERMISSION REQUEST_PERMISSION
) )
} }
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> { else -> {
controller.requestPermissions( controller.requestPermissions(
arrayOf( arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE Manifest.permission.WRITE_EXTERNAL_STORAGE
@ -333,8 +329,6 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
REQUEST_PERMISSION REQUEST_PERMISSION
) )
} }
else -> { // permission is automatically granted on sdk<23 upon installation
}
} }
} }

View File

@ -24,7 +24,6 @@
package com.nextcloud.talk.utils; package com.nextcloud.talk.utils;
import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -67,9 +66,6 @@ import com.nextcloud.talk.utils.text.Spans;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.Date; import java.util.Date;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -82,7 +78,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.annotation.XmlRes; import androidx.annotation.XmlRes;
import androidx.appcompat.widget.AppCompatDrawableManager;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat; import androidx.core.content.res.ResourcesCompat;
import androidx.core.graphics.ColorUtils; import androidx.core.graphics.ColorUtils;
@ -155,31 +150,6 @@ public class DisplayUtils {
return px / context.getResources().getDisplayMetrics().density; return px / context.getResources().getDisplayMetrics().density;
} }
// Solution inspired by https://stackoverflow.com/questions/34936590/why-isnt-my-vector-drawable-scaling-as-expected
public static void useCompatVectorIfNeeded() {
if (Build.VERSION.SDK_INT < 23) {
try {
@SuppressLint("RestrictedApi") AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
Class<?> inflateDelegateClass = Class.forName(
"android.support.v7.widget.AppCompatDrawableManager$InflateDelegate");
Class<?> vdcInflateDelegateClass = Class.forName(
"android.support.v7.widget.AppCompatDrawableManager$VdcInflateDelegate");
Constructor<?> constructor = vdcInflateDelegateClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object vdcInflateDelegate = constructor.newInstance();
Class<?> args[] = {String.class, inflateDelegateClass};
Method addDelegate = AppCompatDrawableManager.class.getDeclaredMethod("addDelegate", args);
addDelegate.setAccessible(true);
addDelegate.invoke(drawableManager, "vector", vdcInflateDelegate);
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
InvocationTargetException | IllegalAccessException e) {
Log.e(TAG, "Failed to use reflection to enable proper vector scaling");
}
}
}
public static Drawable getTintedDrawable(Resources res, @DrawableRes int drawableResId, @ColorRes int colorResId) { public static Drawable getTintedDrawable(Resources res, @DrawableRes int drawableResId, @ColorRes int colorResId) {
Drawable drawable = ResourcesCompat.getDrawable(res, drawableResId, null); Drawable drawable = ResourcesCompat.getDrawable(res, drawableResId, null);
@ -206,10 +176,8 @@ public class DisplayUtils {
viewThemeUtils.material.colorChipDrawable(context, chip); viewThemeUtils.material.colorChipDrawable(context, chip);
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Configuration config = context.getResources().getConfiguration();
Configuration config = context.getResources().getConfiguration(); chip.setLayoutDirection(config.getLayoutDirection());
chip.setLayoutDirection(config.getLayoutDirection());
}
int drawable; int drawable;
@ -386,24 +354,23 @@ public class DisplayUtils {
Window window = activity.getWindow(); Window window = activity.getWindow();
boolean isLightTheme = lightTheme(color); boolean isLightTheme = lightTheme(color);
if (window != null) { if (window != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
View decor = window.getDecorView(); View decor = window.getDecorView();
if (isLightTheme) { if (isLightTheme) {
int systemUiFlagLightStatusBar; int systemUiFlagLightStatusBar;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
systemUiFlagLightStatusBar = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | systemUiFlagLightStatusBar = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR |
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
} else {
systemUiFlagLightStatusBar = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
decor.setSystemUiVisibility(systemUiFlagLightStatusBar);
} else { } else {
decor.setSystemUiVisibility(0); systemUiFlagLightStatusBar = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} }
window.setStatusBarColor(color); decor.setSystemUiVisibility(systemUiFlagLightStatusBar);
} else if (isLightTheme) { } else {
window.setStatusBarColor(Color.BLACK); decor.setSystemUiVisibility(0);
} }
window.setStatusBarColor(color);
} else if (isLightTheme) {
window.setStatusBarColor(Color.BLACK);
} }
} }

View File

@ -218,7 +218,7 @@ object NotificationUtils {
notification: Notification notification: Notification
) -> Unit ) -> Unit
) { ) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || conversationUser.id == -1L || context == null) { if (conversationUser.id == -1L || context == null) {
return return
} }

View File

@ -21,7 +21,6 @@
package com.nextcloud.talk.utils; package com.nextcloud.talk.utils;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Build;
import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties; import android.security.keystore.KeyProperties;
@ -50,7 +49,6 @@ import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException; import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import androidx.annotation.RequiresApi;
import androidx.biometric.BiometricPrompt; import androidx.biometric.BiometricPrompt;
public class SecurityUtils { public class SecurityUtils {
@ -60,7 +58,6 @@ public class SecurityUtils {
private static BiometricPrompt.CryptoObject cryptoObject; private static BiometricPrompt.CryptoObject cryptoObject;
@RequiresApi(api = Build.VERSION_CODES.M)
public static boolean checkIfWeAreAuthenticated(String screenLockTimeout) { public static boolean checkIfWeAreAuthenticated(String screenLockTimeout) {
try { try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
@ -95,12 +92,10 @@ public class SecurityUtils {
} }
} }
@RequiresApi(api = Build.VERSION_CODES.M)
public static BiometricPrompt.CryptoObject getCryptoObject() { public static BiometricPrompt.CryptoObject getCryptoObject() {
return cryptoObject; return cryptoObject;
} }
@RequiresApi(api = Build.VERSION_CODES.M)
public static void createKey(String validity) { public static void createKey(String validity) {
try { try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");

View File

@ -23,7 +23,6 @@ package com.nextcloud.talk.utils.permissions
import android.Manifest import android.Manifest
import android.content.Context import android.content.Context
import android.os.Build
import androidx.core.content.PermissionChecker import androidx.core.content.PermissionChecker
import com.nextcloud.talk.BuildConfig import com.nextcloud.talk.BuildConfig
@ -32,13 +31,9 @@ class PlatformPermissionUtilImpl(private val context: Context) : PlatformPermiss
"${BuildConfig.APPLICATION_ID}.${BuildConfig.PERMISSION_LOCAL_BROADCAST}" "${BuildConfig.APPLICATION_ID}.${BuildConfig.PERMISSION_LOCAL_BROADCAST}"
override fun isCameraPermissionGranted(): Boolean { override fun isCameraPermissionGranted(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return PermissionChecker.checkSelfPermission(
return PermissionChecker.checkSelfPermission( context,
context, Manifest.permission.CAMERA
Manifest.permission.CAMERA ) == PermissionChecker.PERMISSION_GRANTED
) == PermissionChecker.PERMISSION_GRANTED
} else {
true
}
} }
} }

View File

@ -8,12 +8,9 @@
package com.nextcloud.talk.utils.ssl package com.nextcloud.talk.utils.ssl
import android.os.Build
import java.io.IOException
import java.net.InetAddress import java.net.InetAddress
import java.net.Socket import java.net.Socket
import java.security.GeneralSecurityException import java.security.GeneralSecurityException
import java.util.LinkedList
import javax.net.ssl.KeyManager import javax.net.ssl.KeyManager
import javax.net.ssl.SSLContext import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocket
@ -35,69 +32,12 @@ class SSLSocketFactoryCompat(
var cipherSuites: Array<String>? = null var cipherSuites: Array<String>? = null
init { init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Since Android 6.0 (API level 23),
// Since Android 6.0 (API level 23), // - TLSv1.1 and TLSv1.2 is enabled by default
// - TLSv1.1 and TLSv1.2 is enabled by default // - SSLv3 is disabled by default
// - SSLv3 is disabled by default // - all modern ciphers are activated by default
// - all modern ciphers are activated by default protocols = null
protocols = null cipherSuites = null
cipherSuites = null
} else {
val socket = SSLSocketFactory.getDefault().createSocket() as SSLSocket?
try {
socket?.let {
/* set reasonable protocol versions */
// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)
// - remove all SSL versions (especially SSLv3) because they're insecure now
val _protocols = LinkedList<String>()
for (protocol in socket.supportedProtocols.filterNot { it.contains("SSL", true) })
_protocols += protocol
protocols = _protocols.toTypedArray()
/* set up reasonable cipher suites */
val knownCiphers = arrayOf<String>(
// TLS 1.2
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
// maximum interoperability
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
// additionally
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
)
val availableCiphers = socket.supportedCipherSuites
/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus
* disabling ciphers which are enabled by default, but have become unsecure), but for
* the security level of DAVdroid and maximum compatibility, disabling of insecure
* ciphers should be a server-side task */
// for the final set of enabled ciphers, take the ciphers enabled by default, ...
val _cipherSuites = LinkedList<String>()
_cipherSuites.addAll(socket.enabledCipherSuites)
// ... add explicitly allowed ciphers ...
_cipherSuites.addAll(knownCiphers)
// ... and keep only those which are actually available
_cipherSuites.retainAll(availableCiphers)
cipherSuites = _cipherSuites.toTypedArray()
}
} catch (e: IOException) {
// Exception is to be ignored
} finally {
socket?.close() // doesn't implement Closeable on all supported Android versions
}
}
} }
} }

View File

@ -41,7 +41,6 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.media.AudioDeviceInfo; import android.media.AudioDeviceInfo;
import android.media.AudioManager; import android.media.AudioManager;
import android.os.Build;
import android.util.Log; import android.util.Log;
import com.nextcloud.talk.events.PeerConnectionEvent; import com.nextcloud.talk.events.PeerConnectionEvent;
@ -388,22 +387,18 @@ public class WebRtcAudioManager {
*/ */
@Deprecated @Deprecated
private boolean hasWiredHeadset() { private boolean hasWiredHeadset() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { @SuppressLint("WrongConstant") final AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
return audioManager.isWiredHeadsetOn(); for (AudioDeviceInfo device : devices) {
} else { final int type = device.getType();
@SuppressLint("WrongConstant") final AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL); if (type == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
for (AudioDeviceInfo device : devices) { Log.d(TAG, "hasWiredHeadset: found wired headset");
final int type = device.getType(); return true;
if (type == AudioDeviceInfo.TYPE_WIRED_HEADSET) { } else if (type == AudioDeviceInfo.TYPE_USB_DEVICE) {
Log.d(TAG, "hasWiredHeadset: found wired headset"); Log.d(TAG, "hasWiredHeadset: found USB audio device");
return true; return true;
} else if (type == AudioDeviceInfo.TYPE_USB_DEVICE) {
Log.d(TAG, "hasWiredHeadset: found USB audio device");
return true;
}
} }
return false;
} }
return false;
} }
public void updateAudioDeviceState() { public void updateAudioDeviceState() {