Skip to content

ADFA-2738 connectedV8DebugAndroidTest Part 1 of 2: onboarding#1168

Merged
hal-eisen-adfa merged 1 commit into
stagefrom
ADFA-2738-connectedV8DebugAndroidTest-part1-onboarding
Apr 9, 2026
Merged

ADFA-2738 connectedV8DebugAndroidTest Part 1 of 2: onboarding#1168
hal-eisen-adfa merged 1 commit into
stagefrom
ADFA-2738-connectedV8DebugAndroidTest-part1-onboarding

Conversation

@hal-eisen-adfa
Copy link
Copy Markdown
Collaborator

Breaking down the earlier, larger PR into 2 pieces

This one fixes the onboarding flow, especially the granting of permissions

@hal-eisen-adfa hal-eisen-adfa changed the title ADFA-2738 Part 1: onboarding ADFA-2738 connectedV8DebugAndroidTest Part 1: onboarding Apr 9, 2026
@hal-eisen-adfa hal-eisen-adfa requested a review from jatezzz April 9, 2026 02:39
@hal-eisen-adfa hal-eisen-adfa changed the title ADFA-2738 connectedV8DebugAndroidTest Part 1: onboarding ADFA-2738 connectedV8DebugAndroidTest Part 1 of 2: onboarding Apr 9, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 9, 2026

📝 Walkthrough

Release Notes: ADFA-2738 Part 1 - Onboarding Permission Flow Refactor

Key Changes

  • Refactored permission granting in tests: Replaced explicit system permission-granting flows (clicking specific permission buttons and interacting with SystemPermissionsScreen) with a unified onboarding-driven approach via new helper functions
  • New helper utilities added:
    • DevicePermissionGrantUiHelper.kt - Extension functions for UIAutomator interactions with Android system permission/setting dialogs (POST_NOTIFICATIONS, MANAGE_ALL_FILES, INSTALL_PACKAGES, SYSTEM_ALERT_WINDOW)
    • GrantRequiredPermissionsUiHelper.kt - Automates granting all required permissions through onboarding UI based on dynamic permission requirements
    • OnboardingPermissionsInfoHelper.kt - Handles permissions info slide dismissal and privacy dialog acceptance
    • EnsureHomeScreenHelper.kt - Stabilizes navigation after onboarding with screen detection and project closing automation
  • Updated test implementations:
    • PermissionsScreenTest.kt now uses dynamic permission expectations via PermissionsHelper.getRequiredPermissions() instead of hardcoded assumptions
    • NavigateToMainScreenScenario.kt refactored to use new helper-driven permission flows
  • Added new UI element reference: PermissionScreen.finishInstallationButton for accessing the "finish installation" button

Risks & Best Practices Concerns

⚠️ Fragile UI Detection:

  • Permission granting heavily relies on text-based UIAutomator selectors (UiSelector finding by visible text) rather than stable resource IDs. Changes to localized strings or button labels will break these flows.
  • Multiple conditional fallbacks for finding dialog controls (e.g., "Allow", "Authorize", alternative text variations) suggest UI inconsistency across Android versions.

⚠️ Timing & Flakiness:

  • Extensive use of flakySafely with bounded waits (up to 300s for home/editor UI detection) and waitForExists calls indicate potential timing issues. These may mask underlying race conditions.
  • Complex permission grant flows with multiple sequential steps (navigate RecyclerView → click button → wait for system UI → interact with dialog → press back) increase test flakiness risk.

⚠️ Conditional Logic in Test Automation:

  • grantDisplayOverOtherAppsUi() includes conditional Switch state checking and toggle logic that may differ across Android versions/OEM implementations.
  • Post-onboarding screen detection uses heuristics (editor app-bar layout vs "Get started" view) which could be unreliable.

⚠️ State Management:

  • EnsureHomeScreenHelper modifies SharedPreferences (disables auto-open, clears last opened project) during tests, which could interfere with test isolation or affect other parallel test runs.

Scope

  • Test infrastructure changes only (Android instrumented tests)
  • No changes to exported public API signatures
  • Lines changed: +414 additions, -300 deletions

Walkthrough

This change refactors Android instrumentation test permission-granting flows from hardcoded, step-by-step system UI interactions to modular, helper-driven automation. New utility files abstract UIAutomator interactions for various permission types and onboarding navigation, while existing tests are updated to use these helpers instead of inline logic.

Changes

Cohort / File(s) Summary
New Permission Grant Helpers
app/src/androidTest/kotlin/com/itsaky/androidide/helper/DevicePermissionGrantUiHelper.kt, app/src/androidTest/kotlin/com/itsaky/androidide/helper/GrantRequiredPermissionsUiHelper.kt, app/src/androidTest/kotlin/com/itsaky/androidide/helper/OnboardingPermissionsInfoHelper.kt
Added new extension functions automating UIAutomator interactions with Android system permission dialogs and onboarding permission flows; functions include grantPostNotificationsUi(), grantStorageManageAllFilesUi(), grantInstallUnknownAppsUi(), grantDisplayOverOtherAppsUi(), grantAllRequiredPermissionsThroughOnboardingUi(), and passPermissionsInfoSlideWithPrivacyDialog().
Navigation & Screen Detection Helper
app/src/androidTest/kotlin/com/itsaky/androidide/helper/EnsureHomeScreenHelper.kt
Added utilities for post-onboarding navigation stabilization including home screen verification, drawer/project closing automation, and UI polling with configurable timeouts; primary function ensureOnHomeScreenBeforeCreateProject() detects editor vs. home state and forces re-navigation if needed.
Test Refactoring
app/src/androidTest/kotlin/com/itsaky/androidide/PermissionsScreenTest.kt, app/src/androidTest/kotlin/com/itsaky/androidide/scenarios/NavigateToMainScreenScenario.kt
Replaced hardcoded permission UI interactions and explicit system permission grant flows with helper-driven automation; updated assertions to dynamically derive from PermissionsHelper.getRequiredPermissions() instead of fixed expectations.
Screen Object Addition
app/src/androidTest/kotlin/com/itsaky/androidide/screens/PermissionScreen.kt
Added finishInstallationButton binding to reference the finish installation UI element in tests.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Instrumentation Test
    participant Onboard as Onboarding UI
    participant Device as UIAutomator Device
    participant SysUI as System Permission Dialog
    participant Android as Android Framework

    Test->>Onboard: passPermissionsInfoSlideWithPrivacyDialog()
    Onboard->>Device: locate & click privacy accept button
    Device->>SysUI: find button by text
    SysUI-->>Device: button located
    Device->>SysUI: click button
    Onboard->>Device: click next button on permissions slide
    Device->>Onboard: advance slide
    
    Test->>Test: grantAllRequiredPermissionsThroughOnboardingUi()
    Test->>Onboard: iterate required permissions
    loop For each required permission
        Onboard->>Onboard: scroll to permission item
        Onboard->>Device: click grant button
        Device->>SysUI: navigate to system permission dialog
        SysUI->>Device: show permission grant UI
        Device->>Device: grantXxxUi() based on permission type
        Device->>SysUI: locate & click allow option
        SysUI->>Android: request permission grant
        Android-->>Device: permission state updated
        Device->>SysUI: press back
    end
    
    Test->>Android: verify all permissions granted
    Android-->>Test: confirmation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • itsaky-adfa
  • jomen-adfa

🐰 Permissions granted with helpers so neat,
No more hardcoded clicks, automation's sweet!
UIAutomator dances through dialogs divine,
Tests now modular—oh, how they shine! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly relates to the changeset which refactors onboarding and permission-granting flows in Android instrumentation tests.
Description check ✅ Passed The description accurately reflects the changeset, which breaks down a larger PR and fixes the onboarding flow with focus on permission granting.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ADFA-2738-connectedV8DebugAndroidTest-part1-onboarding

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
app/src/androidTest/kotlin/com/itsaky/androidide/helper/EnsureHomeScreenHelper.kt (1)

26-30: Intentional use of Log.e for all log levels.

The comment explains the rationale (Gradle often hides println), but using error-level logging for informational messages could clutter logcat filtering. Consider using a custom log tag with Log.i or Log.d for non-error messages if logcat filtering becomes an issue.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/androidTest/kotlin/com/itsaky/androidide/helper/EnsureHomeScreenHelper.kt`
around lines 26 - 30, The helper currently logs all messages at error level via
testLog (using Log.e and System.err.println), which can clutter error filters;
change testLog to use an appropriate level like Log.i or Log.d for non-error
messages (preserve System.err.println for Gradle visibility) and/or introduce a
new method or flag to select Log.e only for real errors; update calls that
expect testLog to remain named testLog and keep TAG unchanged so references to
testLog and TAG still locate the function.
app/src/androidTest/kotlin/com/itsaky/androidide/scenarios/NavigateToMainScreenScenario.kt (1)

19-35: Consider narrowing the exception type in the Welcome Screen click fallback.

The catch block at line 23 catches generic Exception. Per project guidelines, prefer narrow exception handling (e.g., catching specific Espresso/Kaspresso exceptions) to maintain fail-fast behavior for unexpected errors.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/androidTest/kotlin/com/itsaky/androidide/scenarios/NavigateToMainScreenScenario.kt`
around lines 19 - 35, The catch currently swallows all Exceptions when calling
OnboardingScreen.nextButton { click() }; change this to catch only the expected
test/ui exceptions (e.g., NoMatchingViewException and PerformException from
Espresso and UiObjectNotFoundException from UiAutomator) so unexpected failures
still fail fast; update the try/catch around OnboardingScreen.nextButton to
handle those specific exceptions and keep the existing fallback logic that uses
device.uiDevice and UiSelector to find NEXT/Next/Continue.
app/src/androidTest/kotlin/com/itsaky/androidide/helper/DevicePermissionGrantUiHelper.kt (2)

73-100: Unused context parameter in grantDisplayOverOtherAppsUi.

The context: Context parameter is declared but never used in the function body. Either remove it or document its intended future use.

🧹 Proposed fix to remove unused parameter
-fun Device.grantDisplayOverOtherAppsUi(candidates: List<String>, context: Context) {
+fun Device.grantDisplayOverOtherAppsUi(candidates: List<String>) {

Also update the call site in GrantRequiredPermissionsUiHelper.kt:

                     device.grantDisplayOverOtherAppsUi(
                         listOf(
                             appLabel,
                             targetContext.getString(R.string.app_name),
                             targetContext.packageName,
                         ),
-                        targetContext,
                     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/androidTest/kotlin/com/itsaky/androidide/helper/DevicePermissionGrantUiHelper.kt`
around lines 73 - 100, The function Device.grantDisplayOverOtherAppsUi has an
unused context: Context parameter; remove the parameter from the function
signature and update every call site (e.g., in
GrantRequiredPermissionsUiHelper.kt) to call
grantDisplayOverOtherAppsUi(candidates) without the context argument, and adjust
any imports/usages affected by the signature change so the project compiles.

11-71: Silent returns when no matching UI element is found may hide failures.

All grant functions (grantPostNotificationsUi, grantStorageManageAllFilesUi, grantInstallUnknownAppsUi) return silently without logging or throwing if no matching button is found. This could mask issues when system UI changes or on unfamiliar OEM skins.

Consider adding a warning log when no element matches, to aid debugging flaky tests:

💡 Example: Add logging for visibility
fun Device.grantPostNotificationsUi() {
    val d = uiDevice
    d.waitForIdle(1500)
    val labels = listOf("Allow", "While using the app", "Only this time", "Allow notifications")
    for (label in labels) {
        val o = d.findObject(UiSelector().text(label))
        if (o.waitForExists(4000) && o.exists() && o.isEnabled) {
            o.click()
            d.waitForIdle(1500)
            return
        }
    }
    Log.w("DevicePermGrantUi", "grantPostNotificationsUi: no matching button found among $labels")
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/androidTest/kotlin/com/itsaky/androidide/helper/DevicePermissionGrantUiHelper.kt`
around lines 11 - 71, The three grant functions (grantPostNotificationsUi,
grantStorageManageAllFilesUi, grantInstallUnknownAppsUi) silently return when no
matching UI element is found; add a visible warning log at the end of each
function so failures are detectable (e.g., Log.w with a tag like
"DevicePermGrantUi" and include the list variable name — labels or texts — so
the message shows which candidates were attempted). Also ensure android.util.Log
is imported; do not change behavior of the success path, only log when the loop
completes without clicking any element.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@app/src/androidTest/kotlin/com/itsaky/androidide/helper/DevicePermissionGrantUiHelper.kt`:
- Around line 73-100: The function Device.grantDisplayOverOtherAppsUi has an
unused context: Context parameter; remove the parameter from the function
signature and update every call site (e.g., in
GrantRequiredPermissionsUiHelper.kt) to call
grantDisplayOverOtherAppsUi(candidates) without the context argument, and adjust
any imports/usages affected by the signature change so the project compiles.
- Around line 11-71: The three grant functions (grantPostNotificationsUi,
grantStorageManageAllFilesUi, grantInstallUnknownAppsUi) silently return when no
matching UI element is found; add a visible warning log at the end of each
function so failures are detectable (e.g., Log.w with a tag like
"DevicePermGrantUi" and include the list variable name — labels or texts — so
the message shows which candidates were attempted). Also ensure android.util.Log
is imported; do not change behavior of the success path, only log when the loop
completes without clicking any element.

In
`@app/src/androidTest/kotlin/com/itsaky/androidide/helper/EnsureHomeScreenHelper.kt`:
- Around line 26-30: The helper currently logs all messages at error level via
testLog (using Log.e and System.err.println), which can clutter error filters;
change testLog to use an appropriate level like Log.i or Log.d for non-error
messages (preserve System.err.println for Gradle visibility) and/or introduce a
new method or flag to select Log.e only for real errors; update calls that
expect testLog to remain named testLog and keep TAG unchanged so references to
testLog and TAG still locate the function.

In
`@app/src/androidTest/kotlin/com/itsaky/androidide/scenarios/NavigateToMainScreenScenario.kt`:
- Around line 19-35: The catch currently swallows all Exceptions when calling
OnboardingScreen.nextButton { click() }; change this to catch only the expected
test/ui exceptions (e.g., NoMatchingViewException and PerformException from
Espresso and UiObjectNotFoundException from UiAutomator) so unexpected failures
still fail fast; update the try/catch around OnboardingScreen.nextButton to
handle those specific exceptions and keep the existing fallback logic that uses
device.uiDevice and UiSelector to find NEXT/Next/Continue.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d2d2e06a-3e29-4327-a046-0402a11402de

📥 Commits

Reviewing files that changed from the base of the PR and between d300cff and 4bf98a0.

📒 Files selected for processing (7)
  • app/src/androidTest/kotlin/com/itsaky/androidide/PermissionsScreenTest.kt
  • app/src/androidTest/kotlin/com/itsaky/androidide/helper/DevicePermissionGrantUiHelper.kt
  • app/src/androidTest/kotlin/com/itsaky/androidide/helper/EnsureHomeScreenHelper.kt
  • app/src/androidTest/kotlin/com/itsaky/androidide/helper/GrantRequiredPermissionsUiHelper.kt
  • app/src/androidTest/kotlin/com/itsaky/androidide/helper/OnboardingPermissionsInfoHelper.kt
  • app/src/androidTest/kotlin/com/itsaky/androidide/scenarios/NavigateToMainScreenScenario.kt
  • app/src/androidTest/kotlin/com/itsaky/androidide/screens/PermissionScreen.kt

@hal-eisen-adfa hal-eisen-adfa merged commit e0a588a into stage Apr 9, 2026
2 checks passed
@hal-eisen-adfa hal-eisen-adfa deleted the ADFA-2738-connectedV8DebugAndroidTest-part1-onboarding branch April 9, 2026 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants