From f1a5137f66facaadd7255d98567ff1921a85f04a Mon Sep 17 00:00:00 2001 From: Piotr Maszota Date: Fri, 17 Nov 2023 08:40:37 +0100 Subject: [PATCH 1/6] Fix schedule notification on Android 14 phone --- .../android/app/src/main/AndroidManifest.xml | 39 ++++++++++++------- .../permissions/notifications_test.dart | 10 +++++ .../example/lib/notifications_screen.dart | 4 ++ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/packages/patrol/example/android/app/src/main/AndroidManifest.xml b/packages/patrol/example/android/app/src/main/AndroidManifest.xml index 665f19cf5..784e8eac1 100644 --- a/packages/patrol/example/android/app/src/main/AndroidManifest.xml +++ b/packages/patrol/example/android/app/src/main/AndroidManifest.xml @@ -1,14 +1,16 @@ + xmlns:tools="http://schemas.android.com/tools" package="pl.leancode.patrol.example"> - - - - - - - - + + + + + + + + + - - + + + + + + + + + + + + android:value="2" /> - + \ No newline at end of file diff --git a/packages/patrol/example/integration_test/permissions/notifications_test.dart b/packages/patrol/example/integration_test/permissions/notifications_test.dart index 94b3c93a8..7d9ebe0ea 100644 --- a/packages/patrol/example/integration_test/permissions/notifications_test.dart +++ b/packages/patrol/example/integration_test/permissions/notifications_test.dart @@ -11,6 +11,16 @@ void main() { await $.native.grantPermissionWhenInUse(); } + // Android 14+ requires additional permission to schedule notifications + try { + await $.native.tap( + Selector(text: 'Allow setting alarms and reminders'), + ); + await $.native.pressBack(); + } on PatrolActionException catch (_) { + // ignore + } + await $('Show in a few seconds').tap(); await $.native.pressHome(); await $.native.openNotifications(); diff --git a/packages/patrol/example/lib/notifications_screen.dart b/packages/patrol/example/lib/notifications_screen.dart index 884807eeb..09d0cd65e 100644 --- a/packages/patrol/example/lib/notifications_screen.dart +++ b/packages/patrol/example/lib/notifications_screen.dart @@ -43,6 +43,10 @@ class _NotificationsScreenState extends State { .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.requestNotificationsPermission(); + await _notificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.requestExactAlarmsPermission(); }(), ); } From 2210f0d3893ba90c5328b819c6d5a087a8f21b54 Mon Sep 17 00:00:00 2001 From: Piotr Maszota Date: Fri, 17 Nov 2023 08:58:50 +0100 Subject: [PATCH 2/6] Create workflow to run tests on Android 14 --- .github/workflows/test-android-14-device.yaml | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 .github/workflows/test-android-14-device.yaml diff --git a/.github/workflows/test-android-14-device.yaml b/.github/workflows/test-android-14-device.yaml new file mode 100644 index 000000000..4c1b702df --- /dev/null +++ b/.github/workflows/test-android-14-device.yaml @@ -0,0 +1,126 @@ +name: test android device + +on: + workflow_dispatch: + schedule: + - cron: '30 21 * * *' + +jobs: + run_tests: + name: Flutter ${{ matrix.flutter-version }} on ${{ matrix.os }} ${{ matrix.os_version }} + runs-on: ubuntu-latest + timeout-minutes: 30 + outputs: + SLACK_MESSAGE_TITLE: Flutter ${{ matrix.flutter-version }} on ${{ matrix.os }} ${{ matrix.os_version }} + TESTS_EXIT_CODE: ${{ steps.tests_step.outputs.TESTS_EXIT_CODE }} + EXCLUDED_TESTS: ${{ steps.set_excluded_tests.outputs.EXCLUDED_TESTS }} + URL_TO_DETAILS: ${{ steps.tests_step.outputs.URL_TO_DETAILS }} + + strategy: + fail-fast: false + matrix: + flutter-version: ['3.16.x'] + flutter-channel: ['stable'] + device_model: ['shiba'] + os: ['Android API'] + os_version: ['34'] + + defaults: + run: + working-directory: packages/patrol/example + + steps: + - name: Clone repository + uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 17 + + - name: Authenticate to Google Cloud + uses: google-github-actions/auth@v1 + with: + credentials_json: '${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY_JSON }}' + + - name: Set up Cloud SDK + uses: google-github-actions/setup-gcloud@v1 + + - name: Gradle cache + uses: gradle/gradle-build-action@v2 + with: + generate-job-summary: false + + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ matrix.flutter-version }} + channel: ${{ matrix.flutter-channel }} + + - name: Preload Flutter artifacts + run: flutter precache --android + + - name: Set up Melos and activate workspace + working-directory: . + run: | + dart pub global activate melos + melos bootstrap + + - name: Set up Patrol CLI + working-directory: packages/patrol_cli + run: dart pub global activate --source path . && patrol + + - name: Generate Gradle wrapper + run: flutter build apk --config-only + + - name: Set tests to exclude + id: set_excluded_tests + run: | + TESTS_TO_EXCLUDE="service_airplane_mode_test,\ + service_bluetooth_test" + + target_paths="" + for target in $(echo $TESTS_TO_EXCLUDE | tr ',' '\n'); do + target_paths+="integration_test/${target}.dart," + done + target_paths="${target_paths%,}" + + echo "EXCLUDED_TESTS=$TESTS_TO_EXCLUDE" >> "$GITHUB_OUTPUT" + echo "EXCLUDED_TESTS=$target_paths" >> "$GITHUB_ENV" + + - name: patrol build android + run: patrol build android --exclude ${{ env.EXCLUDED_TESTS }} --verbose + + - name: Upload APKs to Firebase Test Lab and wait for tests to finish + id: tests_step + env: + ANDROID_DEVICE_MODEL: ${{ matrix.device_model }} + ANDROID_DEVICE_VERSION: ${{ matrix.os_version }} + run: | + set +e + output="$(./run_android_testlab 2>&1)" + TESTS_EXIT_CODE=$? + set -e + + echo "$output" + + # Extract the last link using grep, tail, and sed, and write it to Github Summmary + link="$(echo "$output" | grep -o 'https://[^ ]*' | tail -1 | sed 's/\[//;s/\]//')" + echo "[Test details on Firebase Test Lab]($link) (LeanCode members only)" >> "$GITHUB_STEP_SUMMARY" + + echo "URL_TO_DETAILS=$link" >> "$GITHUB_OUTPUT" + echo "TESTS_EXIT_CODE=$TESTS_EXIT_CODE" >> "$GITHUB_OUTPUT" + exit $TESTS_EXIT_CODE + + call_send_slack_message: + name: Notify on Slack + uses: ./.github/workflows/send-slack-message.yaml + needs: run_tests + if: always() + with: + TESTS_EXIT_CODE: ${{ needs.run_tests.outputs.TESTS_EXIT_CODE }} + SLACK_MESSAGE_TITLE: ${{ needs.run_tests.outputs.SLACK_MESSAGE_TITLE }} + EXCLUDED_TESTS: ${{ needs.run_tests.outputs.EXCLUDED_TESTS }} + URL_TO_DETAILS: ${{ needs.run_tests.outputs.URL_TO_DETAILS }} + secrets: inherit From 83184329adb524befb4771d256ecc60c6ba33a8d Mon Sep 17 00:00:00 2001 From: Piotr Maszota Date: Fri, 17 Nov 2023 13:33:04 +0100 Subject: [PATCH 3/6] Use workaround for checkign permission page & remove additional workflow --- .github/workflows/test-android-14-device.yaml | 126 ------------------ .github/workflows/test-android-device.yaml | 8 +- .../permissions/notifications_test.dart | 17 ++- 3 files changed, 16 insertions(+), 135 deletions(-) delete mode 100644 .github/workflows/test-android-14-device.yaml diff --git a/.github/workflows/test-android-14-device.yaml b/.github/workflows/test-android-14-device.yaml deleted file mode 100644 index 4c1b702df..000000000 --- a/.github/workflows/test-android-14-device.yaml +++ /dev/null @@ -1,126 +0,0 @@ -name: test android device - -on: - workflow_dispatch: - schedule: - - cron: '30 21 * * *' - -jobs: - run_tests: - name: Flutter ${{ matrix.flutter-version }} on ${{ matrix.os }} ${{ matrix.os_version }} - runs-on: ubuntu-latest - timeout-minutes: 30 - outputs: - SLACK_MESSAGE_TITLE: Flutter ${{ matrix.flutter-version }} on ${{ matrix.os }} ${{ matrix.os_version }} - TESTS_EXIT_CODE: ${{ steps.tests_step.outputs.TESTS_EXIT_CODE }} - EXCLUDED_TESTS: ${{ steps.set_excluded_tests.outputs.EXCLUDED_TESTS }} - URL_TO_DETAILS: ${{ steps.tests_step.outputs.URL_TO_DETAILS }} - - strategy: - fail-fast: false - matrix: - flutter-version: ['3.16.x'] - flutter-channel: ['stable'] - device_model: ['shiba'] - os: ['Android API'] - os_version: ['34'] - - defaults: - run: - working-directory: packages/patrol/example - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Set up Java - uses: actions/setup-java@v3 - with: - distribution: temurin - java-version: 17 - - - name: Authenticate to Google Cloud - uses: google-github-actions/auth@v1 - with: - credentials_json: '${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY_JSON }}' - - - name: Set up Cloud SDK - uses: google-github-actions/setup-gcloud@v1 - - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - with: - generate-job-summary: false - - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ matrix.flutter-version }} - channel: ${{ matrix.flutter-channel }} - - - name: Preload Flutter artifacts - run: flutter precache --android - - - name: Set up Melos and activate workspace - working-directory: . - run: | - dart pub global activate melos - melos bootstrap - - - name: Set up Patrol CLI - working-directory: packages/patrol_cli - run: dart pub global activate --source path . && patrol - - - name: Generate Gradle wrapper - run: flutter build apk --config-only - - - name: Set tests to exclude - id: set_excluded_tests - run: | - TESTS_TO_EXCLUDE="service_airplane_mode_test,\ - service_bluetooth_test" - - target_paths="" - for target in $(echo $TESTS_TO_EXCLUDE | tr ',' '\n'); do - target_paths+="integration_test/${target}.dart," - done - target_paths="${target_paths%,}" - - echo "EXCLUDED_TESTS=$TESTS_TO_EXCLUDE" >> "$GITHUB_OUTPUT" - echo "EXCLUDED_TESTS=$target_paths" >> "$GITHUB_ENV" - - - name: patrol build android - run: patrol build android --exclude ${{ env.EXCLUDED_TESTS }} --verbose - - - name: Upload APKs to Firebase Test Lab and wait for tests to finish - id: tests_step - env: - ANDROID_DEVICE_MODEL: ${{ matrix.device_model }} - ANDROID_DEVICE_VERSION: ${{ matrix.os_version }} - run: | - set +e - output="$(./run_android_testlab 2>&1)" - TESTS_EXIT_CODE=$? - set -e - - echo "$output" - - # Extract the last link using grep, tail, and sed, and write it to Github Summmary - link="$(echo "$output" | grep -o 'https://[^ ]*' | tail -1 | sed 's/\[//;s/\]//')" - echo "[Test details on Firebase Test Lab]($link) (LeanCode members only)" >> "$GITHUB_STEP_SUMMARY" - - echo "URL_TO_DETAILS=$link" >> "$GITHUB_OUTPUT" - echo "TESTS_EXIT_CODE=$TESTS_EXIT_CODE" >> "$GITHUB_OUTPUT" - exit $TESTS_EXIT_CODE - - call_send_slack_message: - name: Notify on Slack - uses: ./.github/workflows/send-slack-message.yaml - needs: run_tests - if: always() - with: - TESTS_EXIT_CODE: ${{ needs.run_tests.outputs.TESTS_EXIT_CODE }} - SLACK_MESSAGE_TITLE: ${{ needs.run_tests.outputs.SLACK_MESSAGE_TITLE }} - EXCLUDED_TESTS: ${{ needs.run_tests.outputs.EXCLUDED_TESTS }} - URL_TO_DETAILS: ${{ needs.run_tests.outputs.URL_TO_DETAILS }} - secrets: inherit diff --git a/.github/workflows/test-android-device.yaml b/.github/workflows/test-android-device.yaml index c59ae7162..d3b76238e 100644 --- a/.github/workflows/test-android-device.yaml +++ b/.github/workflows/test-android-device.yaml @@ -21,9 +21,13 @@ jobs: matrix: flutter-version: ['3.16.x'] flutter-channel: ['stable'] - device_model: ['oriole'] + device_model: ['oriole', 'shiba'] os: ['Android API'] - os_version: ['33'] + include: + - device_model: 'oriole' + os_version: '33' + - device_model: 'shiba' + os_version: '34' defaults: run: diff --git a/packages/patrol/example/integration_test/permissions/notifications_test.dart b/packages/patrol/example/integration_test/permissions/notifications_test.dart index 7d9ebe0ea..4f8417574 100644 --- a/packages/patrol/example/integration_test/permissions/notifications_test.dart +++ b/packages/patrol/example/integration_test/permissions/notifications_test.dart @@ -11,14 +11,17 @@ void main() { await $.native.grantPermissionWhenInUse(); } - // Android 14+ requires additional permission to schedule notifications - try { - await $.native.tap( - Selector(text: 'Allow setting alarms and reminders'), - ); + // Android 14+ requires additional permission to schedule notifications. + // Workaround for conditionally granting permission. + final android14PermissionSelector = Selector( + text: 'Allow setting alarms and reminders', + ); + final android14PermissionScreen = await $.native.getNativeViews( + android14PermissionSelector, + ); + if (android14PermissionScreen.isNotEmpty) { + await $.native.tap(android14PermissionSelector); await $.native.pressBack(); - } on PatrolActionException catch (_) { - // ignore } await $('Show in a few seconds').tap(); From af59ef487a8eabef32dc9631e414c250c3117dc9 Mon Sep 17 00:00:00 2001 From: Piotr Maszota Date: Fri, 17 Nov 2023 13:39:00 +0100 Subject: [PATCH 4/6] Remove unnecessary device_model array from workflow --- .github/workflows/test-android-device.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-android-device.yaml b/.github/workflows/test-android-device.yaml index d3b76238e..e9398cde4 100644 --- a/.github/workflows/test-android-device.yaml +++ b/.github/workflows/test-android-device.yaml @@ -21,7 +21,6 @@ jobs: matrix: flutter-version: ['3.16.x'] flutter-channel: ['stable'] - device_model: ['oriole', 'shiba'] os: ['Android API'] include: - device_model: 'oriole' From 6d8cc457cc647510fd5b4436c6abdd3c8dab2248 Mon Sep 17 00:00:00 2001 From: Piotr Maszota Date: Fri, 17 Nov 2023 13:51:53 +0100 Subject: [PATCH 5/6] Revert formatting in AndroidManifest.xml --- .../android/app/src/main/AndroidManifest.xml | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/patrol/example/android/app/src/main/AndroidManifest.xml b/packages/patrol/example/android/app/src/main/AndroidManifest.xml index 784e8eac1..c43725ebb 100644 --- a/packages/patrol/example/android/app/src/main/AndroidManifest.xml +++ b/packages/patrol/example/android/app/src/main/AndroidManifest.xml @@ -1,17 +1,23 @@ xmlns:tools="http://schemas.android.com/tools" package="pl.leancode.patrol.example"> - + - + + + + + + - + + + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" /> - - + + + android:value="2"/> - \ No newline at end of file + + From 89f84e8986aeab22fec7a6e2ac161a19cb9425ba Mon Sep 17 00:00:00 2001 From: Piotr Maszota Date: Fri, 17 Nov 2023 13:59:09 +0100 Subject: [PATCH 6/6] Use correct AndroidManifest.xml --- .../android/app/src/main/AndroidManifest.xml | 38 +++++++------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/packages/patrol/example/android/app/src/main/AndroidManifest.xml b/packages/patrol/example/android/app/src/main/AndroidManifest.xml index c43725ebb..015f75a4a 100644 --- a/packages/patrol/example/android/app/src/main/AndroidManifest.xml +++ b/packages/patrol/example/android/app/src/main/AndroidManifest.xml @@ -1,23 +1,16 @@ - xmlns:tools="http://schemas.android.com/tools" package="pl.leancode.patrol.example"> + xmlns:tools="http://schemas.android.com/tools" package="pl.leancode.patrol.example"> - - - - - - + - - android:name="io.flutter.embedding.android.NormalTheme" - android:resource="@style/NormalTheme" /> @@ -47,22 +37,20 @@ + android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" /> - - - - - - - + android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver"> + + + + + + + - android:value="2"/> + android:value="2"/> - - + \ No newline at end of file