From 4f2b1543a0c6345f60a6b1bfaa44ec631752cae4 Mon Sep 17 00:00:00 2001 From: Ademola Fadumo Date: Wed, 9 Sep 2026 12:47:06 +0100 Subject: [PATCH 1/2] ci: add an Android Lint workflow and gate the Kotlin modules on it --- .github/workflows/lint.yml | 46 + auth/build.gradle.kts | 14 +- auth/lint-baseline.xml | 2264 +++++++++++++++++ auth/src/main/AndroidManifest.xml | 7 +- .../firebase/ui/auth/AuthFlowController.kt | 6 +- .../auth/configuration/AuthUIConfiguration.kt | 2 +- .../ui/auth/ui/components/QrCodeImage.kt | 17 +- .../drawable/fui_ic_facebook_white_22dp.xml | 4 +- .../layout/fui_confirmation_code_layout.xml | 112 - auth/src/main/res/layout/fui_phone_layout.xml | 97 - build.gradle.kts | 20 + common/build.gradle.kts | 1 - database/build.gradle.kts | 1 - .../ui/database/paging/DatabasePagingKey.java | 6 +- .../database/paging/DatabasePagingSource.java | 2 +- firestore/build.gradle.kts | 1 - .../lint/internal/LintIssueRegistry.kt | 8 + internal/lintchecks/build.gradle.kts | 1 - library/build.gradle.kts | 3 +- library/quality/lint-baseline.xml | 19 - okf-bundle/ci-workflows/android.md | 14 + okf-bundle/ci-workflows/index.md | 1 + okf-bundle/modules/index.md | 20 +- okf-bundle/testing/agent-command-policy.md | 40 +- okf-bundle/testing/validation-checklist.md | 21 +- proguard-tests/build.gradle.kts | 1 - scripts/build.sh | 3 + storage/build.gradle.kts | 1 - 28 files changed, 2465 insertions(+), 267 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 auth/lint-baseline.xml delete mode 100644 auth/src/main/res/layout/fui_confirmation_code_layout.xml delete mode 100644 auth/src/main/res/layout/fui_phone_layout.xml delete mode 100644 library/quality/lint-baseline.xml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..a6d5269d33 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,46 @@ +name: Android Lint + +# pull_request only, matching e2e_test.yml. android.yml's [pull_request, push] +# is why every commit there produces two identical `build` runs. +on: + - pull_request + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Cache Gradle packages + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + + - name: Set up JDK 21 + uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0 + with: + java-version: '21' + distribution: 'temurin' + + # lintAll gates :proguard-tests, which applies the google-services plugin and + # will not configure without this file. Mirrors what scripts/build.sh copies. + - name: Copy google-services.json + run: | + cp library/google-services.json app/google-services.json + cp library/google-services.json proguard-tests/google-services.json + + - name: Android Lint + run: ./gradlew --max-workers=2 lintAll + + - name: Print Logs + if: failure() + run: ./scripts/print_build_logs.sh diff --git a/auth/build.gradle.kts b/auth/build.gradle.kts index b4a700553d..a7afe7801f 100644 --- a/auth/build.gradle.kts +++ b/auth/build.gradle.kts @@ -53,14 +53,24 @@ android { "DuplicateStrings", "LocaleFolder", "IconLocation", - "VectorPath" + "VectorPath", + "RtlEnabled", // A library cannot decide this; the consuming app declares it + // Satisfied by any enclosing if(), so it flags 5 of this module's 23 Log.d calls + // and misses the rest. Guarding those 5 with Log.isLoggable does not protect them, + // it silences them: the default per-tag level is INFO. Two of the five are wanted + // in field reports (PhoneAuthScreen.kt "Logged, not silent") and carry no user + // data; the other three log an email, a display name and a verificationId, which + // needs redaction rather than a guard — CPRN-440, which also owns re-enabling this. + "LogConditional" ) checkAllWarnings = true warningsAsErrors = true abortOnError = true - baseline = file("$rootDir/library/quality/lint-baseline.xml") + // Pre-existing debt only: 168 localization findings (CPRN-432) and 12 Compose + // correctness findings (CPRN-436). Every entry is suppressed; new ones still fail. + baseline = file("lint-baseline.xml") } testOptions { diff --git a/auth/lint-baseline.xml b/auth/lint-baseline.xml new file mode 100644 index 0000000000..92a8aae581 --- /dev/null +++ b/auth/lint-baseline.xml @@ -0,0 +1,2264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/src/main/AndroidManifest.xml b/auth/src/main/AndroidManifest.xml index 29f9d060e5..45a4e5a625 100644 --- a/auth/src/main/AndroidManifest.xml +++ b/auth/src/main/AndroidManifest.xml @@ -34,10 +34,15 @@ android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/> + + android:exported="false" + tools:ignore="RedundantLabel" /> provider.validate(context) is AuthProvider.Facebook -> provider.validate(context) is AuthProvider.GenericOAuth -> provider.validate() - else -> null + else -> {} } } diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/components/QrCodeImage.kt b/auth/src/main/java/com/firebase/ui/auth/ui/components/QrCodeImage.kt index 754aa5cc78..22b358a3b2 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/components/QrCodeImage.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/components/QrCodeImage.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.core.graphics.createBitmap import com.google.zxing.BarcodeFormat import com.google.zxing.EncodeHintType import com.google.zxing.WriterException @@ -97,7 +98,7 @@ private fun generateQrCodeBitmap( hints ) - val bitmap = Bitmap.createBitmap(sizePx, sizePx, Bitmap.Config.ARGB_8888) + val bitmap = createBitmap(sizePx, sizePx) val foregroundArgb = android.graphics.Color.argb( (foregroundColor.alpha * 255).toInt(), @@ -113,15 +114,15 @@ private fun generateQrCodeBitmap( (backgroundColor.blue * 255).toInt() ) - for (x in 0 until sizePx) { - for (y in 0 until sizePx) { - bitmap.setPixel( - x, - y, - if (bitMatrix[x, y]) foregroundArgb else backgroundArgb - ) + // One bulk copy rather than sizePx^2 setPixel calls: at the default 250.dp rendered + // at 2x that is 250,000 JNI crossings on the composition thread. + val pixels = IntArray(sizePx * sizePx) + for (y in 0 until sizePx) { + for (x in 0 until sizePx) { + pixels[y * sizePx + x] = if (bitMatrix[x, y]) foregroundArgb else backgroundArgb } } + bitmap.setPixels(pixels, 0, sizePx, 0, 0, sizePx, sizePx) bitmap } catch (e: WriterException) { diff --git a/auth/src/main/res/drawable/fui_ic_facebook_white_22dp.xml b/auth/src/main/res/drawable/fui_ic_facebook_white_22dp.xml index 85afe860da..8b1102de03 100644 --- a/auth/src/main/res/drawable/fui_ic_facebook_white_22dp.xml +++ b/auth/src/main/res/drawable/fui_ic_facebook_white_22dp.xml @@ -1,6 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/auth/src/main/res/layout/fui_phone_layout.xml b/auth/src/main/res/layout/fui_phone_layout.xml deleted file mode 100644 index 3ed6d1be61..0000000000 --- a/auth/src/main/res/layout/fui_phone_layout.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - -