diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index 5a212bffb..a4a49b8ee 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -1,6 +1,7 @@ name: Build on: + workflow_dispatch: push: branches: - main @@ -29,16 +30,19 @@ jobs: - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: 21 - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + build-scan-publish: true + build-scan-terms-of-use-url: "https://gradle.com/terms-of-service" + build-scan-terms-of-use-agree: "yes" - name: Check build-logic run: ./gradlew :build-logic:convention:check @@ -139,11 +143,26 @@ jobs: name: lint-reports path: '**/build/reports/lint-results-*.html' - - name: Upload lint reports (SARIF) - if: ${{ !cancelled() && hashFiles('**/*.sarif') != '' }} + - name: Upload lint reports (SARIF) for app module + if: ${{ !cancelled() && hashFiles('app/**/*.sarif') != '' }} uses: github/codeql-action/upload-sarif@v3 with: - sarif_file: './' + sarif_file: './app/' + category: app + + - name: Upload lint reports (SARIF) for app-nia-catalog module + if: ${{ !cancelled() && hashFiles('app-nia-catalog/**/*.sarif') != '' }} + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: './app-nia-catalog/' + category: app-nia-catalog + + - name: Upload lint reports (SARIF) for lint module + if: ${{ !cancelled() && hashFiles('lint/**/*.sarif') != '' }} + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: './lint/' + category: lint - name: Check badging run: ./gradlew :app:checkProdReleaseBadging @@ -180,16 +199,19 @@ jobs: - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: 21 - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + build-scan-publish: true + build-scan-terms-of-use-url: "https://gradle.com/terms-of-service" + build-scan-terms-of-use-agree: "yes" - name: Build projects and run instrumentation tests uses: reactivecircus/android-emulator-runner@v2 diff --git a/.github/workflows/NightlyBaselineProfiles.yaml b/.github/workflows/NightlyBaselineProfiles.yaml index 6e7354476..43d4b73fa 100644 --- a/.github/workflows/NightlyBaselineProfiles.yaml +++ b/.github/workflows/NightlyBaselineProfiles.yaml @@ -1,6 +1,7 @@ name: NightlyBaselineProfiles on: + workflow_dispatch: schedule: - cron: '42 4 * * *' @@ -39,6 +40,9 @@ jobs: uses: gradle/actions/setup-gradle@v4 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + build-scan-publish: true + build-scan-terms-of-use-url: "https://gradle.com/terms-of-service" + build-scan-terms-of-use-agree: "yes" - name: Setup Android SDK uses: android-actions/setup-android@v3 diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index b952ccb50..4c764a51d 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -1,6 +1,7 @@ name: GitHub Release with APKs on: + workflow_dispatch: push: tags: - 'v*' @@ -36,6 +37,9 @@ jobs: uses: gradle/actions/setup-gradle@v4 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + build-scan-publish: true + build-scan-terms-of-use-url: "https://gradle.com/terms-of-service" + build-scan-terms-of-use-agree: "yes" - name: Setup Android SDK uses: android-actions/setup-android@v3 @@ -75,4 +79,4 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: app/build/outputs/apk/demo/release/app-demo-release.apk asset_name: app-demo-release.apk - asset_content_type: application/vnd.android.package-archive + asset_content_type: application/vnd.android.package-archive diff --git a/AGENT.md b/AGENT.md new file mode 100644 index 000000000..efb39ef19 --- /dev/null +++ b/AGENT.md @@ -0,0 +1,58 @@ +# Now in Android Project + +Now in Android is a native Android mobile application written in Kotlin. It provides regular news +about Android development. Users can choose to follow topics, be notified when new content is +available, and bookmark items. + +## Architecture + +This project is a modern Android application that follows the official architecture guidance from Google. It is a reactive, single-activity app that uses the following: + +- **UI:** Built entirely with Jetpack Compose, including Material 3 components and adaptive layouts for different screen sizes. +- **State Management:** Unidirectional Data Flow (UDF) is implemented using Kotlin Coroutines and `Flow`s. `ViewModel`s act as state holders, exposing UI state as streams of data. +- **Dependency Injection:** Hilt is used for dependency injection throughout the app, simplifying the management of dependencies and improving testability. +- **Navigation:** Navigation is handled by Jetpack Navigation 2 for Compose, allowing for a declarative and type-safe way to navigate between screens. +- **Data:** The data layer is implemented using the repository pattern. + - **Local Data:** Room and DataStore are used for local data persistence. + - **Remote Data:** Retrofit and OkHttp are used for fetching data from the network. +- **Background Processing:** WorkManager is used for deferrable background tasks. + +## Modules + +The main Android app lives in the `app/` folder. Feature modules live in `feature/` and core and shared modules in `core/`. + +## Commands to Build & Test + +The app and Android libraries have two product flavors: `demo` and `prod`, and two build types: `debug` and `release`. + +- Build: `./gradlew assemble{Variant}`. Typically `assembleDemoDebug`. +- Fix linting/formatting: `./gradlew --init-script gradle/init.gradle.kts spotlessApply` +- Run local tests: `./gradlew {variant}Test` +- Run single test: `./gradlew {variant}Test --tests "com.example.myapp.MyTestClass"` +- Run local screenshot tests: `./gradlew verifyRoborazziDemoDebug` + +### Instrumented tests + +- Gradle-managed devices to run on device tests: `./gradlew pixel6api31aospDebugAndroidTest`. Also `pixel4api30aospatdDebugAndroidTest` and `pixelcapi30aospatdDebugAndroidTest`. + +### Creating tests + +#### Instrumented tests + +- Tests for UI features should only use `ComposeTestRule` with a `ComponentActivity`. +- Bigger tests live in the `:app` module and they can start activities like `MainActivity`. + +#### Local tests + +- [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) for most assertions +- [cashapp/turbine](https://github.com/cashapp/turbine) for complex coroutine tests +- [google/truth](https://github.com/google/truth) for assertions + +## Continuous integration + +- The workflows are defined in `.github/workflows/*.yaml` and they contain various checks. +- Screenshot tests are generated by CI, so they shouldn't be checked into the repo from a workstation. + +## Version control and code location + +- The project uses git and is hosted in https://github.com/android/nowinandroid. diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..db0882010 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @dturner diff --git a/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt b/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt index 1943bc6cf..0f95113e3 100644 --- a/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt +++ b/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt @@ -1,7 +1,7 @@ androidx.activity:activity-compose:1.9.3 androidx.activity:activity-ktx:1.9.3 androidx.activity:activity:1.9.3 -androidx.annotation:annotation-experimental:1.4.1 +androidx.annotation:annotation-experimental:1.5.1 androidx.annotation:annotation-jvm:1.9.1 androidx.annotation:annotation:1.9.1 androidx.appcompat:appcompat-resources:1.6.1 @@ -9,53 +9,58 @@ androidx.arch.core:core-common:2.2.0 androidx.arch.core:core-runtime:2.2.0 androidx.autofill:autofill:1.0.0 androidx.browser:browser:1.8.0 -androidx.collection:collection-jvm:1.5.0-beta03 -androidx.collection:collection-ktx:1.5.0-beta03 -androidx.collection:collection:1.5.0-beta03 -androidx.compose.animation:animation-android:1.8.0-beta02 -androidx.compose.animation:animation-core-android:1.8.0-beta02 -androidx.compose.animation:animation-core:1.8.0-beta02 -androidx.compose.animation:animation:1.8.0-beta02 -androidx.compose.foundation:foundation-android:1.8.0-beta02 -androidx.compose.foundation:foundation-layout-android:1.8.0-beta02 -androidx.compose.foundation:foundation-layout:1.8.0-beta02 -androidx.compose.foundation:foundation:1.8.0-beta02 -androidx.compose.material3.adaptive:adaptive-android:1.1.0-rc01 -androidx.compose.material3.adaptive:adaptive:1.1.0-rc01 -androidx.compose.material3:material3-adaptive-navigation-suite-android:1.4.0-alpha08 -androidx.compose.material3:material3-adaptive-navigation-suite:1.4.0-alpha08 -androidx.compose.material3:material3-android:1.4.0-alpha08 -androidx.compose.material3:material3:1.4.0-alpha08 +androidx.collection:collection-jvm:1.5.0 +androidx.collection:collection-ktx:1.5.0 +androidx.collection:collection:1.5.0 +androidx.compose.animation:animation-android:1.10.0-alpha02 +androidx.compose.animation:animation-core-android:1.10.0-alpha02 +androidx.compose.animation:animation-core:1.10.0-alpha02 +androidx.compose.animation:animation:1.10.0-alpha02 +androidx.compose.foundation:foundation-android:1.10.0-alpha02 +androidx.compose.foundation:foundation-layout-android:1.10.0-alpha02 +androidx.compose.foundation:foundation-layout:1.10.0-alpha02 +androidx.compose.foundation:foundation:1.10.0-alpha02 +androidx.compose.material3.adaptive:adaptive-android:1.2.0-beta01 +androidx.compose.material3.adaptive:adaptive:1.2.0-beta01 +androidx.compose.material3:material3-adaptive-navigation-suite-android:1.5.0-alpha03 +androidx.compose.material3:material3-adaptive-navigation-suite:1.5.0-alpha03 +androidx.compose.material3:material3-android:1.5.0-alpha03 +androidx.compose.material3:material3:1.5.0-alpha03 androidx.compose.material:material-icons-core-android:1.7.8 androidx.compose.material:material-icons-core:1.7.8 androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 -androidx.compose.material:material-ripple-android:1.8.0-beta02 -androidx.compose.material:material-ripple:1.8.0-beta02 -androidx.compose.runtime:runtime-android:1.8.0-beta02 -androidx.compose.runtime:runtime-saveable-android:1.8.0-beta02 -androidx.compose.runtime:runtime-saveable:1.8.0-beta02 -androidx.compose.runtime:runtime:1.8.0-beta02 -androidx.compose.ui:ui-android:1.8.0-beta02 -androidx.compose.ui:ui-geometry-android:1.8.0-beta02 -androidx.compose.ui:ui-geometry:1.8.0-beta02 -androidx.compose.ui:ui-graphics-android:1.8.0-beta02 -androidx.compose.ui:ui-graphics:1.8.0-beta02 -androidx.compose.ui:ui-text-android:1.8.0-beta02 -androidx.compose.ui:ui-text:1.8.0-beta02 -androidx.compose.ui:ui-tooling-preview-android:1.8.0-beta02 -androidx.compose.ui:ui-tooling-preview:1.8.0-beta02 -androidx.compose.ui:ui-unit-android:1.8.0-beta02 -androidx.compose.ui:ui-unit:1.8.0-beta02 -androidx.compose.ui:ui-util-android:1.8.0-beta02 -androidx.compose.ui:ui-util:1.8.0-beta02 -androidx.compose.ui:ui:1.8.0-beta02 -androidx.compose:compose-bom-alpha:2025.02.00 +androidx.compose.material:material-ripple-android:1.10.0-alpha02 +androidx.compose.material:material-ripple:1.10.0-alpha02 +androidx.compose.runtime:runtime-android:1.10.0-alpha02 +androidx.compose.runtime:runtime-annotation-android:1.10.0-alpha02 +androidx.compose.runtime:runtime-annotation:1.10.0-alpha02 +androidx.compose.runtime:runtime-saveable-android:1.10.0-alpha02 +androidx.compose.runtime:runtime-saveable:1.10.0-alpha02 +androidx.compose.runtime:runtime:1.10.0-alpha02 +androidx.compose.ui:ui-android:1.10.0-alpha02 +androidx.compose.ui:ui-geometry-android:1.10.0-alpha02 +androidx.compose.ui:ui-geometry:1.10.0-alpha02 +androidx.compose.ui:ui-graphics-android:1.10.0-alpha02 +androidx.compose.ui:ui-graphics:1.10.0-alpha02 +androidx.compose.ui:ui-text-android:1.10.0-alpha02 +androidx.compose.ui:ui-text:1.10.0-alpha02 +androidx.compose.ui:ui-tooling-preview-android:1.10.0-alpha02 +androidx.compose.ui:ui-tooling-preview:1.10.0-alpha02 +androidx.compose.ui:ui-unit-android:1.10.0-alpha02 +androidx.compose.ui:ui-unit:1.10.0-alpha02 +androidx.compose.ui:ui-util-android:1.10.0-alpha02 +androidx.compose.ui:ui-util:1.10.0-alpha02 +androidx.compose.ui:ui:1.10.0-alpha02 +androidx.compose:compose-bom-alpha:2025.08.01 androidx.concurrent:concurrent-futures:1.1.0 -androidx.core:core-ktx:1.13.1 -androidx.core:core:1.13.1 +androidx.core:core-ktx:1.16.0 +androidx.core:core-viewtree:1.0.0 +androidx.core:core:1.16.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.0.0 +androidx.documentfile:documentfile:1.0.0 +androidx.dynamicanimation:dynamicanimation:1.0.0 androidx.emoji2:emoji2:1.4.0 androidx.exifinterface:exifinterface:1.3.7 androidx.fragment:fragment:1.5.1 @@ -63,39 +68,46 @@ androidx.graphics:graphics-path:1.0.1 androidx.graphics:graphics-shapes-android:1.0.1 androidx.graphics:graphics-shapes:1.0.1 androidx.interpolator:interpolator:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.8.7 -androidx.lifecycle:lifecycle-common-jvm:2.8.7 -androidx.lifecycle:lifecycle-common:2.8.7 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.7 -androidx.lifecycle:lifecycle-livedata-core:2.8.7 -androidx.lifecycle:lifecycle-livedata:2.8.7 -androidx.lifecycle:lifecycle-process:2.8.7 -androidx.lifecycle:lifecycle-runtime-android:2.8.7 -androidx.lifecycle:lifecycle-runtime-compose-android:2.8.7 -androidx.lifecycle:lifecycle-runtime-compose:2.8.7 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.7 -androidx.lifecycle:lifecycle-runtime-ktx:2.8.7 -androidx.lifecycle:lifecycle-runtime:2.8.7 -androidx.lifecycle:lifecycle-viewmodel-android:2.8.7 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.7 -androidx.lifecycle:lifecycle-viewmodel:2.8.7 +androidx.legacy:legacy-support-core-utils:1.0.0 +androidx.lifecycle:lifecycle-common-java8:2.10.0-alpha03 +androidx.lifecycle:lifecycle-common-jvm:2.10.0-alpha03 +androidx.lifecycle:lifecycle-common:2.10.0-alpha03 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.10.0-alpha03 +androidx.lifecycle:lifecycle-livedata-core:2.10.0-alpha03 +androidx.lifecycle:lifecycle-livedata:2.10.0-alpha03 +androidx.lifecycle:lifecycle-process:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-compose-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-compose:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-ktx:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel:2.10.0-alpha03 androidx.loader:loader:1.0.0 +androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 androidx.metrics:metrics-performance:1.0.0-beta01 +androidx.print:print:1.0.0 androidx.profileinstaller:profileinstaller:1.4.0 -androidx.savedstate:savedstate-ktx:1.2.1 -androidx.savedstate:savedstate:1.2.1 +androidx.savedstate:savedstate-android:1.4.0-alpha03 +androidx.savedstate:savedstate-compose-android:1.4.0-alpha03 +androidx.savedstate:savedstate-compose:1.4.0-alpha03 +androidx.savedstate:savedstate-ktx:1.4.0-alpha03 +androidx.savedstate:savedstate:1.4.0-alpha03 androidx.startup:startup-runtime:1.1.1 androidx.tracing:tracing-ktx:1.3.0-alpha02 androidx.tracing:tracing:1.3.0-alpha02 +androidx.transition:transition:1.6.0 androidx.vectordrawable:vectordrawable-animated:1.1.0 androidx.vectordrawable:vectordrawable:1.1.0 androidx.versionedparcelable:versionedparcelable:1.1.1 androidx.viewpager:viewpager:1.0.0 -androidx.window.extensions.core:core:1.0.0 -androidx.window:window-core-android:1.3.0 -androidx.window:window-core:1.3.0 -androidx.window:window:1.3.0 +androidx.window:window-core-android:1.4.0 +androidx.window:window-core:1.4.0 +androidx.window:window:1.4.0 com.google.accompanist:accompanist-drawablepainter:0.32.0 com.google.code.findbugs:jsr305:3.0.2 com.google.dagger:dagger-lint-aar:2.56 @@ -123,5 +135,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1 org.jetbrains.kotlinx:kotlinx-datetime:0.6.1 +org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.3 +org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.3 +org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3 org.jetbrains:annotations:23.0.0 org.jspecify:jspecify:1.0.0 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ffeb52e01..60884a3b5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -45,7 +45,8 @@ android { release { isMinifyEnabled = true applicationIdSuffix = NiaBuildType.RELEASE.applicationIdSuffix - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt")) + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro") // To publish on the Play store a private signing key is required, but to allow anyone // who clones the code to sign and run the release variant, use the debug signing key. @@ -61,11 +62,7 @@ android { excludes.add("/META-INF/{AL2.0,LGPL2.1}") } } - testOptions { - unitTests { - isIncludeAndroidResources = true - } - } + testOptions.unitTests.isIncludeAndroidResources = true namespace = "com.google.samples.apps.nowinandroid" } diff --git a/app/dependencies/prodReleaseRuntimeClasspath.txt b/app/dependencies/prodReleaseRuntimeClasspath.txt index 18ec55cbd..ae9639b62 100644 --- a/app/dependencies/prodReleaseRuntimeClasspath.txt +++ b/app/dependencies/prodReleaseRuntimeClasspath.txt @@ -1,7 +1,7 @@ -androidx.activity:activity-compose:1.9.3 -androidx.activity:activity-ktx:1.9.3 -androidx.activity:activity:1.9.3 -androidx.annotation:annotation-experimental:1.4.1 +androidx.activity:activity-compose:1.10.1 +androidx.activity:activity-ktx:1.10.1 +androidx.activity:activity:1.10.1 +androidx.annotation:annotation-experimental:1.5.1 androidx.annotation:annotation-jvm:1.9.1 androidx.annotation:annotation:1.9.1 androidx.appcompat:appcompat-resources:1.7.0 @@ -10,60 +10,63 @@ androidx.arch.core:core-common:2.2.0 androidx.arch.core:core-runtime:2.2.0 androidx.autofill:autofill:1.0.0 androidx.browser:browser:1.8.0 -androidx.collection:collection-jvm:1.5.0-beta03 -androidx.collection:collection-ktx:1.5.0-beta03 -androidx.collection:collection:1.5.0-beta03 -androidx.compose.animation:animation-android:1.8.0-beta02 -androidx.compose.animation:animation-core-android:1.8.0-beta02 -androidx.compose.animation:animation-core:1.8.0-beta02 -androidx.compose.animation:animation:1.8.0-beta02 -androidx.compose.foundation:foundation-android:1.8.0-beta02 -androidx.compose.foundation:foundation-layout-android:1.8.0-beta02 -androidx.compose.foundation:foundation-layout:1.8.0-beta02 -androidx.compose.foundation:foundation:1.8.0-beta02 -androidx.compose.material3.adaptive:adaptive-android:1.1.0-rc01 -androidx.compose.material3.adaptive:adaptive-layout-android:1.1.0-rc01 -androidx.compose.material3.adaptive:adaptive-layout:1.1.0-rc01 -androidx.compose.material3.adaptive:adaptive-navigation-android:1.1.0-rc01 -androidx.compose.material3.adaptive:adaptive-navigation:1.1.0-rc01 -androidx.compose.material3.adaptive:adaptive:1.1.0-rc01 -androidx.compose.material3:material3-adaptive-navigation-suite-android:1.4.0-alpha08 -androidx.compose.material3:material3-adaptive-navigation-suite:1.4.0-alpha08 -androidx.compose.material3:material3-android:1.4.0-alpha08 -androidx.compose.material3:material3-window-size-class-android:1.4.0-alpha08 -androidx.compose.material3:material3-window-size-class:1.4.0-alpha08 -androidx.compose.material3:material3:1.4.0-alpha08 +androidx.collection:collection-jvm:1.5.0 +androidx.collection:collection-ktx:1.5.0 +androidx.collection:collection:1.5.0 +androidx.compose.animation:animation-android:1.10.0-alpha02 +androidx.compose.animation:animation-core-android:1.10.0-alpha02 +androidx.compose.animation:animation-core:1.10.0-alpha02 +androidx.compose.animation:animation:1.10.0-alpha02 +androidx.compose.foundation:foundation-android:1.10.0-alpha02 +androidx.compose.foundation:foundation-layout-android:1.10.0-alpha02 +androidx.compose.foundation:foundation-layout:1.10.0-alpha02 +androidx.compose.foundation:foundation:1.10.0-alpha02 +androidx.compose.material3.adaptive:adaptive-android:1.2.0-beta01 +androidx.compose.material3.adaptive:adaptive-layout-android:1.2.0-beta01 +androidx.compose.material3.adaptive:adaptive-layout:1.2.0-beta01 +androidx.compose.material3.adaptive:adaptive-navigation-android:1.2.0-beta01 +androidx.compose.material3.adaptive:adaptive-navigation:1.2.0-beta01 +androidx.compose.material3.adaptive:adaptive:1.2.0-beta01 +androidx.compose.material3:material3-adaptive-navigation-suite-android:1.5.0-alpha03 +androidx.compose.material3:material3-adaptive-navigation-suite:1.5.0-alpha03 +androidx.compose.material3:material3-android:1.5.0-alpha03 +androidx.compose.material3:material3-window-size-class-android:1.5.0-alpha03 +androidx.compose.material3:material3-window-size-class:1.5.0-alpha03 +androidx.compose.material3:material3:1.5.0-alpha03 androidx.compose.material:material-icons-core-android:1.7.8 androidx.compose.material:material-icons-core:1.7.8 androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 -androidx.compose.material:material-ripple-android:1.8.0-beta02 -androidx.compose.material:material-ripple:1.8.0-beta02 -androidx.compose.runtime:runtime-android:1.8.0-beta02 -androidx.compose.runtime:runtime-saveable-android:1.8.0-beta02 -androidx.compose.runtime:runtime-saveable:1.8.0-beta02 -androidx.compose.runtime:runtime-tracing:1.8.0-beta02 -androidx.compose.runtime:runtime:1.8.0-beta02 -androidx.compose.ui:ui-android:1.8.0-beta02 -androidx.compose.ui:ui-geometry-android:1.8.0-beta02 -androidx.compose.ui:ui-geometry:1.8.0-beta02 -androidx.compose.ui:ui-graphics-android:1.8.0-beta02 -androidx.compose.ui:ui-graphics:1.8.0-beta02 -androidx.compose.ui:ui-text-android:1.8.0-beta02 -androidx.compose.ui:ui-text:1.8.0-beta02 -androidx.compose.ui:ui-tooling-preview-android:1.8.0-beta02 -androidx.compose.ui:ui-tooling-preview:1.8.0-beta02 -androidx.compose.ui:ui-unit-android:1.8.0-beta02 -androidx.compose.ui:ui-unit:1.8.0-beta02 -androidx.compose.ui:ui-util-android:1.8.0-beta02 -androidx.compose.ui:ui-util:1.8.0-beta02 -androidx.compose.ui:ui:1.8.0-beta02 -androidx.compose:compose-bom-alpha:2025.02.00 +androidx.compose.material:material-ripple-android:1.10.0-alpha02 +androidx.compose.material:material-ripple:1.10.0-alpha02 +androidx.compose.runtime:runtime-android:1.10.0-alpha02 +androidx.compose.runtime:runtime-annotation-android:1.10.0-alpha02 +androidx.compose.runtime:runtime-annotation:1.10.0-alpha02 +androidx.compose.runtime:runtime-saveable-android:1.10.0-alpha02 +androidx.compose.runtime:runtime-saveable:1.10.0-alpha02 +androidx.compose.runtime:runtime-tracing:1.10.0-alpha02 +androidx.compose.runtime:runtime:1.10.0-alpha02 +androidx.compose.ui:ui-android:1.10.0-alpha02 +androidx.compose.ui:ui-geometry-android:1.10.0-alpha02 +androidx.compose.ui:ui-geometry:1.10.0-alpha02 +androidx.compose.ui:ui-graphics-android:1.10.0-alpha02 +androidx.compose.ui:ui-graphics:1.10.0-alpha02 +androidx.compose.ui:ui-text-android:1.10.0-alpha02 +androidx.compose.ui:ui-text:1.10.0-alpha02 +androidx.compose.ui:ui-tooling-preview-android:1.10.0-alpha02 +androidx.compose.ui:ui-tooling-preview:1.10.0-alpha02 +androidx.compose.ui:ui-unit-android:1.10.0-alpha02 +androidx.compose.ui:ui-unit:1.10.0-alpha02 +androidx.compose.ui:ui-util-android:1.10.0-alpha02 +androidx.compose.ui:ui-util:1.10.0-alpha02 +androidx.compose.ui:ui:1.10.0-alpha02 +androidx.compose:compose-bom-alpha:2025.08.01 androidx.concurrent:concurrent-futures-ktx:1.1.0 androidx.concurrent:concurrent-futures:1.1.0 -androidx.core:core-ktx:1.15.0 +androidx.core:core-ktx:1.16.0 androidx.core:core-splashscreen:1.0.1 -androidx.core:core:1.15.0 +androidx.core:core-viewtree:1.0.0 +androidx.core:core:1.16.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.0.0 @@ -79,6 +82,7 @@ androidx.datastore:datastore-preferences:1.1.1 androidx.datastore:datastore:1.1.1 androidx.documentfile:documentfile:1.0.0 androidx.drawerlayout:drawerlayout:1.0.0 +androidx.dynamicanimation:dynamicanimation:1.0.0 androidx.emoji2:emoji2-views-helper:1.4.0 androidx.emoji2:emoji2:1.4.0 androidx.exifinterface:exifinterface:1.3.7 @@ -92,26 +96,27 @@ androidx.hilt:hilt-navigation:1.2.0 androidx.hilt:hilt-work:1.2.0 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.8.7 -androidx.lifecycle:lifecycle-common-jvm:2.8.7 -androidx.lifecycle:lifecycle-common:2.8.7 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.7 -androidx.lifecycle:lifecycle-livedata-core:2.8.7 -androidx.lifecycle:lifecycle-livedata:2.8.7 -androidx.lifecycle:lifecycle-process:2.8.7 -androidx.lifecycle:lifecycle-runtime-android:2.8.7 -androidx.lifecycle:lifecycle-runtime-compose-android:2.8.7 -androidx.lifecycle:lifecycle-runtime-compose:2.8.7 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.7 -androidx.lifecycle:lifecycle-runtime-ktx:2.8.7 -androidx.lifecycle:lifecycle-runtime:2.8.7 -androidx.lifecycle:lifecycle-service:2.8.7 -androidx.lifecycle:lifecycle-viewmodel-android:2.8.7 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.7 -androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.7 -androidx.lifecycle:lifecycle-viewmodel:2.8.7 +androidx.lifecycle:lifecycle-common-java8:2.10.0-alpha03 +androidx.lifecycle:lifecycle-common-jvm:2.10.0-alpha03 +androidx.lifecycle:lifecycle-common:2.10.0-alpha03 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.10.0-alpha03 +androidx.lifecycle:lifecycle-livedata-core:2.10.0-alpha03 +androidx.lifecycle:lifecycle-livedata:2.10.0-alpha03 +androidx.lifecycle:lifecycle-process:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-compose-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-compose:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime-ktx:2.10.0-alpha03 +androidx.lifecycle:lifecycle-runtime:2.10.0-alpha03 +androidx.lifecycle:lifecycle-service:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-compose:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.10.0-alpha03 +androidx.lifecycle:lifecycle-viewmodel:2.10.0-alpha03 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 androidx.metrics:metrics-performance:1.0.0-beta01 @@ -125,25 +130,32 @@ androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 androidx.profileinstaller:profileinstaller:1.4.1 androidx.resourceinspection:resourceinspection-annotation:1.0.1 -androidx.room:room-common:2.6.1 -androidx.room:room-ktx:2.6.1 -androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-ktx:1.2.1 -androidx.savedstate:savedstate:1.2.1 -androidx.sqlite:sqlite-framework:2.4.0 -androidx.sqlite:sqlite:2.4.0 +androidx.room:room-common-jvm:2.7.2 +androidx.room:room-common:2.7.2 +androidx.room:room-ktx:2.7.2 +androidx.room:room-runtime-android:2.7.2 +androidx.room:room-runtime:2.7.2 +androidx.savedstate:savedstate-android:1.4.0-alpha03 +androidx.savedstate:savedstate-compose-android:1.4.0-alpha03 +androidx.savedstate:savedstate-compose:1.4.0-alpha03 +androidx.savedstate:savedstate-ktx:1.4.0-alpha03 +androidx.savedstate:savedstate:1.4.0-alpha03 +androidx.sqlite:sqlite-android:2.5.1 +androidx.sqlite:sqlite-framework-android:2.5.1 +androidx.sqlite:sqlite-framework:2.5.1 +androidx.sqlite:sqlite:2.5.1 androidx.startup:startup-runtime:1.1.1 androidx.tracing:tracing-ktx:1.3.0-alpha02 androidx.tracing:tracing-perfetto:1.0.0 androidx.tracing:tracing:1.3.0-alpha02 +androidx.transition:transition:1.6.0 androidx.vectordrawable:vectordrawable-animated:1.1.0 androidx.vectordrawable:vectordrawable:1.1.0 androidx.versionedparcelable:versionedparcelable:1.1.1 androidx.viewpager:viewpager:1.0.0 -androidx.window.extensions.core:core:1.0.0 -androidx.window:window-core-android:1.3.0 -androidx.window:window-core:1.3.0 -androidx.window:window:1.3.0 +androidx.window:window-core-android:1.4.0 +androidx.window:window-core:1.4.0 +androidx.window:window:1.4.0 androidx.work:work-runtime-ktx:2.10.0 androidx.work:work-runtime:2.10.0 com.caverock:androidsvg-aar:1.4 diff --git a/app/prodRelease-badging.txt b/app/prodRelease-badging.txt index ca03c1088..640949857 100644 --- a/app/prodRelease-badging.txt +++ b/app/prodRelease-badging.txt @@ -1,5 +1,5 @@ package: name='com.google.samples.apps.nowinandroid' versionCode='8' versionName='0.1.2' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' -minSdkVersion:'21' +minSdkVersion:'23' targetSdkVersion:'35' uses-permission: name='android.permission.INTERNET' uses-permission: name='android.permission.ACCESS_NETWORK_STATE' @@ -105,9 +105,9 @@ application-icon-640:'res/mipmap-anydpi-v26/ic_launcher.xml' application-icon-65534:'res/mipmap-anydpi-v26/ic_launcher.xml' application: label='Now in Android' icon='res/mipmap-anydpi-v26/ic_launcher.xml' launchable-activity: name='com.google.samples.apps.nowinandroid.MainActivity' label='' icon='' -uses-library-not-required:'android.ext.adservices' uses-library-not-required:'androidx.window.extensions' uses-library-not-required:'androidx.window.sidecar' +uses-library-not-required:'android.ext.adservices' feature-group: label='' uses-feature: name='android.hardware.faketouch' uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps' diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 000000000..24a0b4a16 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,2 @@ +# Repackage classes into the default package to reduce the size of descriptors. +-repackageclasses diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt index 77f72e5fc..4975e5d65 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt @@ -66,7 +66,7 @@ class NiaApplication : Application(), ImageLoaderFactory { private fun setStrictModePolicy() { if (isDebuggable()) { StrictMode.setThreadPolicy( - Builder().detectAll().penaltyLog().penaltyDeath().build(), + Builder().detectAll().penaltyLog().build(), ) } } diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt index defccdf3f..b237684ef 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt @@ -21,7 +21,9 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.exclude import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing @@ -166,8 +168,7 @@ internal fun NiaApp( ) }, label = { Text(stringResource(destination.iconTextId)) }, - modifier = - Modifier + modifier = Modifier .testTag("NiaNavItem") .then(if (hasUnread) Modifier.notificationDot() else Modifier), ) @@ -185,7 +186,11 @@ internal fun NiaApp( snackbarHost = { SnackbarHost( snackbarHostState, - modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing), + modifier = Modifier.windowInsetsPadding( + WindowInsets.safeDrawing.exclude( + WindowInsets.ime, + ), + ), ) }, ) { padding -> @@ -216,7 +221,7 @@ internal fun NiaApp( actionIconContentDescription = stringResource( id = settingsR.string.feature_settings_top_app_bar_action_icon_description, ), - colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + colors = TopAppBarDefaults.topAppBarColors( containerColor = Color.Transparent, ), onActionClick = { onTopAppBarActionClick() }, diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index e36f021b0..258993913 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -45,8 +45,8 @@ android { ) } - testOptions.managedDevices.devices { - create("pixel6Api33") { + testOptions.managedDevices.localDevices { + create("pixel6Api33") { device = "Pixel 6" apiLevel = 33 systemImageSource = "aosp" diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index 9890a910a..b3fcb0724 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -37,6 +37,7 @@ kotlin { } dependencies { + compileOnly(libs.android.gradleApiPlugin) compileOnly(libs.android.tools.common) compileOnly(plugin(libs.plugins.android.application)) compileOnly(plugin(libs.plugins.android.library)) diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt index 1ab3a2ca0..f45d664b7 100644 --- a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt @@ -16,7 +16,6 @@ import com.android.build.api.dsl.ApplicationExtension import com.android.build.api.variant.ApplicationAndroidComponentsExtension -import com.android.build.gradle.BaseExtension import com.google.samples.apps.nowinandroid.configureBadgingTasks import com.google.samples.apps.nowinandroid.configureGradleManagedDevices import com.google.samples.apps.nowinandroid.configureKotlinAndroid @@ -44,7 +43,7 @@ class AndroidApplicationConventionPlugin : Plugin { } extensions.configure { configurePrintApksTask(this) - configureBadgingTasks(extensions.getByType(), this) + configureBadgingTasks(extensions.getByType(), this) } } } diff --git a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt index 06f759669..cf48f59a7 100644 --- a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -import com.android.build.gradle.LibraryExtension +import com.android.build.api.dsl.LibraryExtension import com.google.samples.apps.nowinandroid.configureGradleManagedDevices import com.google.samples.apps.nowinandroid.libs import org.gradle.api.Plugin diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt index 19fabf549..63a992b05 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -import com.android.build.gradle.LibraryExtension +import com.android.build.api.dsl.LibraryExtension import com.google.samples.apps.nowinandroid.configureAndroidCompose import org.gradle.api.Plugin import org.gradle.api.Project diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt index 3fe727410..0f6fde884 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt @@ -14,8 +14,8 @@ * limitations under the License. */ +import com.android.build.api.dsl.LibraryExtension import com.android.build.api.variant.LibraryAndroidComponentsExtension -import com.android.build.gradle.LibraryExtension import com.google.samples.apps.nowinandroid.configureFlavors import com.google.samples.apps.nowinandroid.configureGradleManagedDevices import com.google.samples.apps.nowinandroid.configureKotlinAndroid @@ -37,7 +37,8 @@ class AndroidLibraryConventionPlugin : Plugin { extensions.configure { configureKotlinAndroid(this) - defaultConfig.targetSdk = 35 + testOptions.targetSdk = 35 + lint.targetSdk = 35 defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testOptions.animationsDisabled = true configureFlavors(this) diff --git a/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt index 67933f77d..49c2eecec 100644 --- a/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -import com.android.build.gradle.TestExtension +import com.android.build.api.dsl.TestExtension import com.google.samples.apps.nowinandroid.configureGradleManagedDevices import com.google.samples.apps.nowinandroid.configureKotlinAndroid import org.gradle.api.Plugin diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt index ed2a5289b..3d050d86b 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt @@ -42,13 +42,6 @@ internal fun Project.configureAndroidCompose( "implementation"(libs.findLibrary("androidx-compose-ui-tooling-preview").get()) "debugImplementation"(libs.findLibrary("androidx-compose-ui-tooling").get()) } - - testOptions { - unitTests { - // For Robolectric - isIncludeAndroidResources = true - } - } } extensions.configure { diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt index 886c70625..229388001 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt @@ -18,8 +18,8 @@ package com.google.samples.apps.nowinandroid import com.android.SdkConstants import com.android.build.api.artifact.SingleArtifact +import com.android.build.api.dsl.ApplicationExtension import com.android.build.api.variant.ApplicationAndroidComponentsExtension -import com.android.build.gradle.BaseExtension import com.google.common.truth.Truth.assertWithMessage import org.gradle.api.DefaultTask import org.gradle.api.Project @@ -110,7 +110,7 @@ private fun String.capitalized() = replaceFirstChar { } fun Project.configureBadgingTasks( - baseExtension: BaseExtension, + baseExtension: ApplicationExtension, componentsExtension: ApplicationAndroidComponentsExtension, ) { // Registers a callback to be called, when a new variant is configured diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt index 5d396d2a4..2ac96e556 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt @@ -38,7 +38,7 @@ internal fun Project.configureKotlinAndroid( compileSdk = 35 defaultConfig { - minSdk = 21 + minSdk = 23 } compileOptions { diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index 345f8bb2e..3b4bd8ee5 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -22,11 +22,7 @@ plugins { android { namespace = "com.google.samples.apps.nowinandroid.core.data" - testOptions { - unitTests { - isIncludeAndroidResources = true - } - } + testOptions.unitTests.isIncludeAndroidResources = true } dependencies { diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt index c7dfd99d0..ac2b5c8af 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt +++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt @@ -24,9 +24,9 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.model.data.UserData import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource import kotlinx.datetime.Clock -import org.junit.Assert.assertEquals -import org.junit.Assert.assertTrue import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue class UserNewsResourceTest { diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt index a3e373918..1c3ec012a 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt +++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt @@ -36,7 +36,7 @@ class TestNewsResourceDao : NewsResourceDao { private val entitiesStateFlow = MutableStateFlow(emptyList()) - internal var topicCrossReferences: List = listOf() + internal var topicCrossReferences: List = emptyList() override fun getNewsResources( useFilterTopicIds: Boolean, diff --git a/core/database/src/main/kotlin/com/google/samples/apps/nowinandroid/core/database/model/NewsResourceEntity.kt b/core/database/src/main/kotlin/com/google/samples/apps/nowinandroid/core/database/model/NewsResourceEntity.kt index 9450a24ad..5aed1d1c2 100644 --- a/core/database/src/main/kotlin/com/google/samples/apps/nowinandroid/core/database/model/NewsResourceEntity.kt +++ b/core/database/src/main/kotlin/com/google/samples/apps/nowinandroid/core/database/model/NewsResourceEntity.kt @@ -49,5 +49,5 @@ fun NewsResourceEntity.asExternalModel() = NewsResource( headerImageUrl = headerImageUrl, publishDate = publishDate, type = type, - topics = listOf(), + topics = emptyList(), ) diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts index 1161e8ef5..7e7cad9ac 100644 --- a/core/designsystem/build.gradle.kts +++ b/core/designsystem/build.gradle.kts @@ -22,6 +22,7 @@ plugins { android { namespace = "com.google.samples.apps.nowinandroid.core.designsystem" + testOptions.unitTests.isIncludeAndroidResources = true } dependencies { diff --git a/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt b/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt index f85c65677..ece8e0259 100644 --- a/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt +++ b/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt @@ -45,7 +45,7 @@ fun NiaTopAppBar( actionIcon: ImageVector, actionIconContentDescription: String, modifier: Modifier = Modifier, - colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors(), + colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(), onNavigationClick: () -> Unit = {}, onActionClick: () -> Unit = {}, ) { diff --git a/core/designsystem/src/test/screenshots/Navigation/Navigation_fontScale2.png b/core/designsystem/src/test/screenshots/Navigation/Navigation_fontScale2.png index b2dff990a..16df296d5 100644 Binary files a/core/designsystem/src/test/screenshots/Navigation/Navigation_fontScale2.png and b/core/designsystem/src/test/screenshots/Navigation/Navigation_fontScale2.png differ diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 1a8005727..002695a0b 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -14,12 +14,15 @@ * limitations under the License. */ +import com.android.build.api.variant.BuildConfigField +import java.io.StringReader +import java.util.Properties + plugins { alias(libs.plugins.nowinandroid.android.library) alias(libs.plugins.nowinandroid.android.library.jacoco) alias(libs.plugins.nowinandroid.hilt) id("kotlinx-serialization") - id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") } android { @@ -27,15 +30,7 @@ android { buildConfig = true } namespace = "com.google.samples.apps.nowinandroid.core.network" - testOptions { - unitTests { - isIncludeAndroidResources = true - } - } -} - -secrets { - defaultPropertiesFileName = "secrets.defaults.properties" + testOptions.unitTests.isIncludeAndroidResources = true } dependencies { @@ -56,3 +51,19 @@ dependencies { testImplementation(libs.kotlinx.coroutines.test) } + +val backendUrl = providers.fileContents( + isolated.rootProject.projectDirectory.file("local.properties") +).asText.map { text -> + val properties = Properties() + properties.load(StringReader(text)) + properties["BACKEND_URL"] +}.orElse("http://example.com") + +androidComponents { + onVariants { + it.buildConfigFields!!.put("BACKEND_URL", backendUrl.map { value -> + BuildConfigField(type = "String", value = """"$value"""", comment = null) + }) + } +} diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/model/NetworkNewsResource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/model/NetworkNewsResource.kt index 7b66af796..92e8e9ffa 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/model/NetworkNewsResource.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/model/NetworkNewsResource.kt @@ -16,6 +16,7 @@ package com.google.samples.apps.nowinandroid.core.network.model +import android.annotation.SuppressLint import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import kotlinx.datetime.Instant import kotlinx.serialization.Serializable @@ -23,6 +24,7 @@ import kotlinx.serialization.Serializable /** * Network representation of [NewsResource] when fetched from /newsresources */ +@SuppressLint("UnsafeOptInUsageError") @Serializable data class NetworkNewsResource( val id: String, @@ -32,5 +34,5 @@ data class NetworkNewsResource( val headerImageUrl: String, val publishDate: Instant, val type: String, - val topics: List = listOf(), + val topics: List = emptyList(), ) diff --git a/feature/foryou/build.gradle.kts b/feature/foryou/build.gradle.kts index 59f6844cf..de1af7540 100644 --- a/feature/foryou/build.gradle.kts +++ b/feature/foryou/build.gradle.kts @@ -23,6 +23,7 @@ plugins { android { namespace = "com.google.samples.apps.nowinandroid.feature.foryou" + testOptions.unitTests.isIncludeAndroidResources = true } dependencies { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 425e6c0a4..5b97c7c36 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,12 +2,12 @@ accompanist = "0.37.0" androidDesugarJdkLibs = "2.1.4" # AGP and tools should be updated together -androidGradlePlugin = "8.9.0" -androidTools = "31.9.0" +androidGradlePlugin = "8.12.2" +androidTools = "31.12.2" androidxActivity = "1.9.3" androidxAppCompat = "1.7.0" androidxBrowser = "1.8.0" -androidxComposeBom = "2025.02.00" +androidxComposeBom = "2025.08.01" androidxComposeFoundation = "1.8.0-alpha07" androidxComposeMaterial3Adaptive = "1.1.0-rc01" androidxComposeRuntimeTracing = "1.7.6" @@ -21,10 +21,10 @@ androidxMacroBenchmark = "1.3.4" androidxMetrics = "1.0.0-beta01" androidxNavigation = "2.8.5" androidxProfileinstaller = "1.4.1" -androidxTestCore = "1.6.1" -androidxTestExt = "1.2.1" -androidxTestRules = "1.6.1" -androidxTestRunner = "1.6.2" +androidxTestCore = "1.7.0-rc01" +androidxTestExt = "1.3.0-rc01" +androidxTestRules = "1.7.0-rc01" +androidxTestRunner = "1.7.0-rc01" androidxTracing = "1.3.0-alpha02" androidxUiAutomator = "2.3.0" androidxWindowManager = "1.3.0" @@ -32,11 +32,11 @@ androidxWork = "2.10.0" coil = "2.7.0" dependencyGuard = "0.5.0" firebaseBom = "33.7.0" -firebaseCrashlyticsPlugin = "3.0.2" -firebasePerfPlugin = "1.4.2" +firebaseCrashlyticsPlugin = "3.0.6" +firebasePerfPlugin = "2.0.1" gmsPlugin = "4.4.2" googleOss = "17.1.0" -googleOssPlugin = "0.10.6" +googleOssPlugin = "0.10.7" hilt = "2.56" hiltExt = "1.2.0" jacoco = "0.8.12" @@ -53,7 +53,7 @@ protobufPlugin = "0.9.4" retrofit = "2.11.0" robolectric = "4.14.1" roborazzi = "1.39.0" -room = "2.6.1" +room = "2.7.2" secrets = "2.0.1" truth = "1.4.4" turbine = "1.2.0" @@ -157,7 +157,14 @@ truth = { module = "com.google.truth:truth", version.ref = "truth" } turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } # Dependencies of the included build-logic +android-gradleApiPlugin = { group = "com.android.tools.build", name = "gradle-api", version.ref = "androidGradlePlugin" } android-tools-common = { module = "com.android.tools:common", version.ref = "androidTools" } +compose-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" } +firebase-crashlytics-gradlePlugin = { group = "com.google.firebase", name = "firebase-crashlytics-gradle", version.ref = "firebaseCrashlyticsPlugin" } +firebase-performance-gradlePlugin = { group = "com.google.firebase", name = "perf-plugin", version.ref = "firebasePerfPlugin" } +kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } +ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } +room-gradlePlugin = { group = "androidx.room", name = "room-gradle-plugin", version.ref = "room" } [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b953..8bdaf60c7 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 c99f97449..3e781fbad 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip -distributionSha256Sum=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78 +distributionSha256Sum=8fad3d78296ca518113f3d29016617c7f9367dc005f932bd9d93bf45ba46072b +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f3b75f3b0..ef07e0162 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -205,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019c7..5eed7ee84 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/secrets.defaults.properties b/secrets.defaults.properties deleted file mode 100644 index 3b5457bd9..000000000 --- a/secrets.defaults.properties +++ /dev/null @@ -1,4 +0,0 @@ -## This file provides default values to modules using the secrets-gradle-plugin. It is necessary -# because the secrets properties file is not under source control so CI builds will fail without -# default values. -BACKEND_URL="http://example.com" \ No newline at end of file