diff --git a/android/build.gradle b/android/build.gradle index 4d76c40530..12db7f658d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -54,6 +54,10 @@ android { targetCompatibility JavaVersion.VERSION_17 } + lintOptions { + warningsAsErrors true + } + kotlinOptions { jvmTarget = "17" } diff --git a/android/src/main/java/com/tailscale/ipn/AppSourceChecker.kt b/android/src/main/java/com/tailscale/ipn/AppSourceChecker.kt index 72e39fc781..fd4d4d734b 100644 --- a/android/src/main/java/com/tailscale/ipn/AppSourceChecker.kt +++ b/android/src/main/java/com/tailscale/ipn/AppSourceChecker.kt @@ -15,20 +15,21 @@ object AppSourceChecker { val packageName = context.packageName Log.d(TAG, "Package name: $packageName") - val installerPackageName = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - packageManager.getInstallSourceInfo(packageName).installingPackageName - } else { - packageManager.getInstallerPackageName(packageName) - } + val installerPackageName = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + packageManager.getInstallSourceInfo(packageName).installingPackageName + } else { + @Suppress("deprecation") packageManager.getInstallerPackageName(packageName) + } Log.d(TAG, "Installer package name: $installerPackageName") return when (installerPackageName) { - "com.android.vending" -> "googleplay" - "org.fdroid.fdroid" -> "fdroid" - "com.amazon.venezia" -> "amazon" - null -> "unknown" - else -> "unknown($installerPackageName)" + "com.android.vending" -> "googleplay" + "org.fdroid.fdroid" -> "fdroid" + "com.amazon.venezia" -> "amazon" + null -> "unknown" + else -> "unknown($installerPackageName)" } -} + } } diff --git a/android/src/main/java/com/tailscale/ipn/QuickToggleService.java b/android/src/main/java/com/tailscale/ipn/QuickToggleService.java index 7b8355fb4e..0ac3bd0ab6 100644 --- a/android/src/main/java/com/tailscale/ipn/QuickToggleService.java +++ b/android/src/main/java/com/tailscale/ipn/QuickToggleService.java @@ -60,6 +60,7 @@ public void onStopListening() { } } + @SuppressWarnings("deprecation") @Override public void onClick() { boolean r; @@ -77,6 +78,7 @@ public void onClick() { // Request code for opening activity. startActivityAndCollapse(PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)); } else { + // Deprecated, but still required for older versions. startActivityAndCollapse(i); } } diff --git a/android/src/main/java/com/tailscale/ipn/ui/model/Permissions.kt b/android/src/main/java/com/tailscale/ipn/ui/model/Permissions.kt index 8579f0b495..10e4367f51 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/model/Permissions.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/model/Permissions.kt @@ -22,7 +22,7 @@ object Permissions { @Composable get() { val permissionStates = rememberMultiplePermissionsState(permissions = all.map { it.name }) - return all.zip(permissionStates.permissions).filter { (permission, state) -> + return all.zip(permissionStates.permissions).filter { (_, state) -> !state.status.isGranted && !state.status.shouldShowRationale } } diff --git a/android/src/main/java/com/tailscale/ipn/ui/theme/Theme.kt b/android/src/main/java/com/tailscale/ipn/ui/theme/Theme.kt index 7426372479..6af87cfaee 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/theme/Theme.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/theme/Theme.kt @@ -44,7 +44,8 @@ fun AppTheme(useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable // margins in list items. bodyMedium = MaterialTheme.typography.bodyMedium.copy(fontSize = 16.sp)) - val systemUiController = rememberSystemUiController() + // TODO: Migrate to Activity.enableEdgeToEdge + @Suppress("deprecation") val systemUiController = rememberSystemUiController() DisposableEffect(systemUiController, useDarkTheme) { systemUiController.setStatusBarColor(color = colors.surfaceContainer) @@ -446,7 +447,6 @@ val ColorScheme.disabled: Color val ColorScheme.searchBarColors: TextFieldColors @Composable get() { - val defaults = OutlinedTextFieldDefaults.colors() return OutlinedTextFieldDefaults.colors( focusedLeadingIconColor = MaterialTheme.colorScheme.onSurface, unfocusedLeadingIconColor = MaterialTheme.colorScheme.onSurface, diff --git a/android/src/main/java/com/tailscale/ipn/ui/util/AndroidTVUtil.kt b/android/src/main/java/com/tailscale/ipn/ui/util/AndroidTVUtil.kt index bad37f38a7..b4265d2166 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/util/AndroidTVUtil.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/util/AndroidTVUtil.kt @@ -15,7 +15,7 @@ import com.tailscale.ipn.ui.util.AndroidTVUtil.isAndroidTV object AndroidTVUtil { fun isAndroidTV(): Boolean { val pm = UninitializedApp.get().packageManager - return (pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION) || + return (pm.hasSystemFeature(@Suppress("deprecation") PackageManager.FEATURE_TELEVISION) || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) } } diff --git a/android/src/main/java/com/tailscale/ipn/ui/view/ExitNodePicker.kt b/android/src/main/java/com/tailscale/ipn/ui/view/ExitNodePicker.kt index 19bec62a80..6a9396f008 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/view/ExitNodePicker.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/view/ExitNodePicker.kt @@ -61,7 +61,7 @@ fun ExitNodePicker( if (forcedExitNodeId != null) { Text( text = - managedByOrganization?.let { + managedByOrganization.value?.let { stringResource(R.string.exit_node_mdm_orgname, it) } ?: stringResource(R.string.exit_node_mdm), style = MaterialTheme.typography.bodyMedium, diff --git a/android/src/main/java/com/tailscale/ipn/ui/view/MDMSettingsDebugView.kt b/android/src/main/java/com/tailscale/ipn/ui/view/MDMSettingsDebugView.kt index ec6a68a446..ce8e6f45cd 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/view/MDMSettingsDebugView.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/view/MDMSettingsDebugView.kt @@ -25,7 +25,10 @@ import com.tailscale.ipn.ui.viewModel.IpnViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable -fun MDMSettingsDebugView(backToSettings: BackNavigation, model: IpnViewModel = viewModel()) { +fun MDMSettingsDebugView( + backToSettings: BackNavigation, + @Suppress("UNUSED_PARAMETER") model: IpnViewModel = viewModel() +) { Scaffold(topBar = { Header(R.string.current_mdm_settings, onBack = backToSettings) }) { innerPadding -> LazyColumn(modifier = Modifier.padding(innerPadding)) { diff --git a/android/src/main/java/com/tailscale/ipn/ui/view/MainView.kt b/android/src/main/java/com/tailscale/ipn/ui/view/MainView.kt index df19d7883e..9f7e5e055b 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/view/MainView.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/view/MainView.kt @@ -251,7 +251,7 @@ fun MainView( } } - currentPingDevice?.let { peer -> + currentPingDevice?.let { _ -> ModalBottomSheet(onDismissRequest = { viewModel.onPingDismissal() }) { PingView(model = viewModel.pingViewModel) } diff --git a/android/src/main/java/com/tailscale/ipn/ui/view/ManagedByView.kt b/android/src/main/java/com/tailscale/ipn/ui/view/ManagedByView.kt index e66e89adf8..7494e3e8aa 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/view/ManagedByView.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/view/ManagedByView.kt @@ -23,14 +23,16 @@ import com.tailscale.ipn.R import com.tailscale.ipn.mdm.MDMSettings import com.tailscale.ipn.ui.viewModel.IpnViewModel +@Suppress("UNUSED_PARAMETER") @Composable fun ManagedByView(backToSettings: BackNavigation, model: IpnViewModel = viewModel()) { - Scaffold(topBar = { Header(R.string.managed_by, onBack = backToSettings) }) { innerPadding -> + Scaffold(topBar = { Header(R.string.managed_by, onBack = backToSettings) }) { _ -> Column( verticalArrangement = Arrangement.spacedBy(space = 20.dp, alignment = Alignment.CenterVertically), horizontalAlignment = Alignment.Start, - modifier = Modifier.fillMaxWidth().safeContentPadding().verticalScroll(rememberScrollState())) { + modifier = + Modifier.fillMaxWidth().safeContentPadding().verticalScroll(rememberScrollState())) { val managedByOrganization = MDMSettings.managedByOrganizationName.flow.collectAsState().value.value val managedByCaption = MDMSettings.managedByCaption.flow.collectAsState().value.value diff --git a/android/src/main/java/com/tailscale/ipn/ui/viewModel/MainViewModel.kt b/android/src/main/java/com/tailscale/ipn/ui/viewModel/MainViewModel.kt index cdfaacea71..f1c76410c5 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/viewModel/MainViewModel.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/viewModel/MainViewModel.kt @@ -32,6 +32,7 @@ import kotlinx.coroutines.launch import java.time.Duration class MainViewModelFactory(private val vpnViewModel: VpnViewModel) : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { if (modelClass.isAssignableFrom(MainViewModel::class.java)) { return MainViewModel(vpnViewModel) as T