diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6034c096..b4b0cae1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle @@ -29,7 +29,7 @@ jobs: working-directory: ./app/build/outputs/apk/ci/ run: | echo $CI_SIGNING_KS | base64 --decode > keystore.jks - $ANDROID_HOME/build-tools/33.0.0/apksigner sign --in app-ci-unsigned.apk --out app-ci.apk --ks keystore.jks --ks-pass 'env:CI_SIGNING_KS_PASSWORD' + $ANDROID_HOME/build-tools/34.0.0/apksigner sign --in app-ci-unsigned.apk --out app-ci.apk --ks keystore.jks --ks-pass 'env:CI_SIGNING_KS_PASSWORD' - name: Upload APK uses: actions/upload-artifact@v3.1.1 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index fbebdb60..3a29a53e 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle diff --git a/app/build.gradle b/app/build.gradle index 88f4d3de..a6af3cc9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,18 +1,21 @@ plugins { - id 'com.android.application' version '7.2.2' - id 'org.jetbrains.kotlin.android' version '1.8.0' - id 'org.jetbrains.kotlin.kapt' version '1.8.0' - id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.0' - id "org.jetbrains.kotlin.plugin.parcelize" version "1.8.0" + id 'com.android.application' version '8.2.0' + id 'org.jetbrains.kotlin.android' version '1.9.10' + id 'org.jetbrains.kotlin.kapt' version '1.9.10' + id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.10' + id "org.jetbrains.kotlin.plugin.parcelize" version "1.9.10" } android { - compileSdkVersion 33 + namespace 'com.gaurav.avnc' + + compileSdk 34 + ndkVersion "21.4.7075529" defaultConfig { applicationId "com.gaurav.avnc" - minSdkVersion 21 - targetSdkVersion 33 + minSdk 21 + targetSdk 34 versionCode 26 versionName "2.2.3" @@ -58,6 +61,7 @@ android { buildFeatures { dataBinding true + buildConfig true } externalNativeBuild { @@ -77,21 +81,28 @@ android { } } +kotlin { + jvmToolchain(17) +} + dependencies { - implementation "androidx.core:core-ktx:1.9.0" - implementation 'androidx.activity:activity-ktx:1.6.1' - implementation "androidx.fragment:fragment-ktx:1.5.5" - implementation "androidx.appcompat:appcompat:1.6.0" + implementation "androidx.core:core-ktx:1.12.0" + implementation 'androidx.activity:activity-ktx:1.8.2' + implementation "androidx.fragment:fragment-ktx:1.6.2" + implementation "androidx.appcompat:appcompat:1.6.1" implementation "androidx.dynamicanimation:dynamicanimation:1.0.0" implementation "androidx.biometric:biometric-ktx:1.2.0-alpha05" - implementation "androidx.preference:preference-ktx:1.2.0" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" + implementation "androidx.preference:preference-ktx:1.2.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2" implementation "androidx.recyclerview:recyclerview:1.2.1" implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation "androidx.drawerlayout:drawerlayout:1.1.1" - implementation "androidx.room:room-runtime:2.4.3" - implementation "androidx.room:room-ktx:2.4.3" - kapt "androidx.room:room-compiler:2.4.3" + + def roomVersion = "2.6.1" + implementation "androidx.room:room-runtime:$roomVersion" + implementation "androidx.room:room-ktx:$roomVersion" + kapt "androidx.room:room-compiler:$roomVersion" implementation "com.google.android.material:material:1.7.0" implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0' @@ -104,6 +115,6 @@ dependencies { androidTestImplementation "androidx.test.espresso:espresso-intents:3.5.1" androidTestImplementation "androidx.test:rules:1.5.0" androidTestImplementation "androidx.test.ext:junit-ktx:1.1.5" - androidTestImplementation "androidx.room:room-testing:2.4.3" + androidTestImplementation "androidx.room:room-testing:$roomVersion" androidTestImplementation "io.mockk:mockk-android:1.12.0" } \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 816ead77..3ba313a2 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,2 +1,3 @@ -dontobfuscate -keepattributes SourceFile,LineNumberTable +-dontwarn com.google.errorprone.annotations.Immutable diff --git a/app/src/androidTest/java/com/gaurav/avnc/ui/home/ServerListTest.kt b/app/src/androidTest/java/com/gaurav/avnc/ui/home/ServerListTest.kt index 1a2c6254..348f2877 100644 --- a/app/src/androidTest/java/com/gaurav/avnc/ui/home/ServerListTest.kt +++ b/app/src/androidTest/java/com/gaurav/avnc/ui/home/ServerListTest.kt @@ -58,6 +58,7 @@ class ServerListTest { @Before fun before() { runBlocking { dbRule.db.serverProfileDao.insert(testProfile) } + onView(testProfileMatcher()).checkWillBeDisplayed() } @Test diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cd7d06c3..be8e3f98 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,8 +7,7 @@ --> + xmlns:tools="http://schemas.android.com/tools"> diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/IndicatorView.kt b/app/src/main/java/com/gaurav/avnc/ui/home/IndicatorView.kt index d9f57422..29ec2d84 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/home/IndicatorView.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/home/IndicatorView.kt @@ -48,7 +48,7 @@ class IndicatorView(context: Context, attrs: AttributeSet? = null) : View(contex private var profile: ServerProfile? = null private var indicatedProfiles: LiveData>? = null - private val observer = Observer> { isVisible = it?.contains(profile) == true } + private val observer = Observer?> { isVisible = it?.contains(profile) == true } fun setup(profile: ServerProfile, indicatedProfiles: LiveData>) { this.profile = profile diff --git a/app/src/main/java/com/gaurav/avnc/ui/vnc/LoginFragment.kt b/app/src/main/java/com/gaurav/avnc/ui/vnc/LoginFragment.kt index 2e8e51c9..1fe1866b 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/vnc/LoginFragment.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/vnc/LoginFragment.kt @@ -110,8 +110,8 @@ class LoginFragment : DialogFragment() { private fun saveLoginInfo(loginInfo: LoginInfo) { // Use activity as owner because this fragment will likely be destroyed before connecting viewModel.state.observe(requireActivity(), object : Observer { - override fun onChanged(t: VncViewModel.State?) { - if (t == VncViewModel.State.Connected) { + override fun onChanged(value: VncViewModel.State) { + if (value == VncViewModel.State.Connected) { setLoginInfoInProfile(viewModel.profile, loginInfo) viewModel.saveProfile() viewModel.state.removeObserver(this) diff --git a/app/src/main/java/com/gaurav/avnc/ui/vnc/TouchHandler.kt b/app/src/main/java/com/gaurav/avnc/ui/vnc/TouchHandler.kt index eef49ee2..4a6abd6d 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/vnc/TouchHandler.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/vnc/TouchHandler.kt @@ -339,7 +339,7 @@ class TouchHandler(private val viewModel: VncViewModel, private val dispatcher: listener.onLongPress(e) } - override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { + override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { listener.onFling(velocityX, velocityY) return true } diff --git a/app/src/main/java/com/gaurav/avnc/ui/vnc/VncActivity.kt b/app/src/main/java/com/gaurav/avnc/ui/vnc/VncActivity.kt index 8ac2389a..dcf61b15 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/vnc/VncActivity.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/vnc/VncActivity.kt @@ -372,7 +372,7 @@ class VncActivity : AppCompatActivity() { val detector = GestureDetector(drawerLayout.context, object : GestureDetector.SimpleOnGestureListener() { - override fun onFling(e1: MotionEvent, e2: MotionEvent, vX: Float, vY: Float): Boolean { + override fun onFling(e1: MotionEvent?, e2: MotionEvent, vX: Float, vY: Float): Boolean { val absGravity = Gravity.getAbsoluteGravity(drawerGravity, drawerLayout.layoutDirection) if ((absGravity == Gravity.LEFT && vX < 0) || (absGravity == Gravity.RIGHT && vX > 0)) { drawerLayout.closeDrawer(drawerGravity) diff --git a/app/src/main/java/com/gaurav/avnc/viewmodel/HomeViewModel.kt b/app/src/main/java/com/gaurav/avnc/viewmodel/HomeViewModel.kt index f8865047..8876c700 100644 --- a/app/src/main/java/com/gaurav/avnc/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/com/gaurav/avnc/viewmodel/HomeViewModel.kt @@ -11,7 +11,7 @@ package com.gaurav.avnc.viewmodel import android.app.Application import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.Transformations +import androidx.lifecycle.switchMap import androidx.lifecycle.viewModelScope import com.gaurav.avnc.model.ServerProfile import com.gaurav.avnc.vnc.Discovery @@ -23,7 +23,7 @@ class HomeViewModel(app: Application) : BaseViewModel(app) { * Depending on the user pref, this list may be sorted by server name. */ val serverProfiles by lazy { - Transformations.switchMap(pref.ui.sortServerList) { + pref.ui.sortServerList.switchMap { if (it) serverProfileDao.getSortedLiveList() else serverProfileDao.getLiveList() } @@ -142,7 +142,7 @@ class HomeViewModel(app: Application) : BaseViewModel(app) { * them, but that has its own issues. **************************************************************************/ val rediscoveredProfiles by lazy { - Transformations.switchMap(pref.server.rediscoveryIndicator) { + pref.server.rediscoveryIndicator.switchMap { if (it) prepareRediscoveredProfiles() else MutableLiveData(null) } diff --git a/app/src/main/java/com/gaurav/avnc/vnc/Discovery.kt b/app/src/main/java/com/gaurav/avnc/vnc/Discovery.kt index 483cd5b2..e6901203 100644 --- a/app/src/main/java/com/gaurav/avnc/vnc/Discovery.kt +++ b/app/src/main/java/com/gaurav/avnc/vnc/Discovery.kt @@ -137,6 +137,7 @@ class Discovery(private val context: Context) { */ private inner class DiscoveryListener : NsdManager.DiscoveryListener { override fun onServiceFound(serviceInfo: NsdServiceInfo?) { + @Suppress("DEPRECATION") nsdManager?.resolveService(serviceInfo, ResolveListener()) } @@ -170,6 +171,7 @@ class Discovery(private val context: Context) { */ private inner class ResolveListener : NsdManager.ResolveListener { override fun onServiceResolved(serviceInfo: NsdServiceInfo) { + @Suppress("DEPRECATION") addProfile(serviceInfo.serviceName, serviceInfo.host.hostAddress!!, serviceInfo.port) } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f..033e24c4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1280e44d..ddcc7f3c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,8 @@ -#Sat Oct 22 21:09:10 IST 2022 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionSha256Sum=7c3ad722e9b0ce8205b91560fd6ce8296ac3eadf065672242fd73c06b8eeb6ee +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip -distributionSha256Sum=b586e04868a22fd817c8971330fec37e298f3242eb85c374181b12d637f80302 \ No newline at end of file +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/gradlew b/gradlew index 1b6c7873..fcb6fca1 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +130,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,6 +197,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in @@ -205,6 +213,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f9..6689b85b 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal