Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

refactor: break down AppInstallProcessor into collaborator classes

Description

This MR refactors AppInstallProcessor into smaller, tightly scoped, unit-testable components while preserving current behaviour and keeping the public API (mostly) unchanged.

Please review the MR commit by commit to understand how the refactoring evolved. Otherwise, you can review the changes at once; for your aid in the review process, a diagram, and a guide have been added in the Technical details section.

Technical details

Before refactor

Before the refactor, AppInstallProcessor was effectively the central class for almost all install-related responsibilities.

classDiagram
    class AppInstallProcessor_PreRefactor {
        +initAppInstall(...)
        +enqueueFusedDownload(...)
        +canEnqueue(...)
        +validateAgeLimit(...)
        +awaitInvokeAgeLimitEvent(...)
        +updateDownloadUrls(...)
        +processInstall(...)
        +checkDownloadingState(...)
        +startAppInstallationProcess(...)
        +handleFusedDownloadStatus(...)
        +checkUpdateWork(...)
        +showNotificationOnUpdateEnded(...)
    }

    class EventBus
    class StorageComputer
    class ParentalControlAuthenticator
    class UpdatesDao
    class UpdatesNotifier
    class AppInstallComponents
    class ApplicationRepository
    class AppLoungeDataStore
    class StorageNotificationManager
    class DownloadManagerUtils
    class AppManager
    class ValidateAppAgeLimitUseCase

    AppInstallProcessor_PreRefactor --> AppInstallComponents
    AppInstallProcessor_PreRefactor --> ApplicationRepository
    AppInstallProcessor_PreRefactor --> AppLoungeDataStore
    AppInstallProcessor_PreRefactor --> StorageNotificationManager
    AppInstallProcessor_PreRefactor --> DownloadManagerUtils
    AppInstallProcessor_PreRefactor --> AppManager
    AppInstallProcessor_PreRefactor --> ValidateAppAgeLimitUseCase
    AppInstallProcessor_PreRefactor --> EventBus
    AppInstallProcessor_PreRefactor --> StorageComputer
    AppInstallProcessor_PreRefactor --> ParentalControlAuthenticator
    AppInstallProcessor_PreRefactor --> UpdatesDao
    AppInstallProcessor_PreRefactor --> UpdatesNotifier

After refactor

This diagram gives a reviewer-friendly starting point for the install/update flow under:

  • app/src/main/java/foundation/e/apps/data/install/core/
  • app/src/main/java/foundation/e/apps/data/install/core/helper/
  • data/src/main/java/foundation/e/apps/data/installation/core/

It also includes the small remaining boundary types used by that flow:

  • app/src/main/java/foundation/e/apps/data/install/wrapper/AppEventDispatcher.kt
  • data/src/main/java/foundation/e/apps/data/installation/port/InstallationDownloadStatusUpdater.kt
  • data/src/main/java/foundation/e/apps/data/installation/port/InstallationCompletionNotifier.kt
classDiagram
direction LR

class AppInstallationFacade
class InstallationRequest
class InstallationEnqueuer
class PreEnqueueChecker
class DownloadUrlRefresher
class AgeLimiter
class DevicePreconditions
class InstallationProcessor
class AppManager
class InstallationDownloadStatusUpdater
class InstallationCompletionNotifier
class InstallationCompletionHandler
class AppEventDispatcher
class ParentalControlAuthenticator
class StorageComputer
class UpdatesDao
class UpdatesNotifier

AppInstallationFacade --> InstallationRequest : creates AppInstall
AppInstallationFacade --> InstallationEnqueuer : enqueue path
AppInstallationFacade --> InstallationProcessor : process path

InstallationEnqueuer --> PreEnqueueChecker : validates before enqueue
PreEnqueueChecker --> DownloadUrlRefresher
PreEnqueueChecker --> AgeLimiter
PreEnqueueChecker --> DevicePreconditions

AgeLimiter --> AppEventDispatcher : emits age-limit event
AgeLimiter --> ParentalControlAuthenticator : awaits PIN auth

DevicePreconditions --> AppEventDispatcher : emits device errors
DevicePreconditions --> StorageComputer : checks free space

InstallationProcessor --> AppManager : install and status changes
InstallationProcessor --> InstallationDownloadStatusUpdater : refreshes downloads
InstallationProcessor --> InstallationCompletionNotifier : finishes update flow

InstallationCompletionNotifier <|.. InstallationCompletionHandler
InstallationCompletionHandler --> AppManager : reads install result
InstallationCompletionHandler --> UpdatesDao : tracks updated apps
InstallationCompletionHandler --> UpdatesNotifier : shows update summary

Reading guide

  • Start at AppInstallationFacade.
  • The enqueue side stays in app: InstallationRequest -> InstallationEnqueuer -> PreEnqueueChecker.
  • PreEnqueueChecker fans out into three app-side checks: URL refresh, age-limit validation, and device preconditions.
  • AppEventDispatcher remains as a small app-local seam for event dispatch.
  • The processing side lives across app and data: InstallationProcessor is in data, and it only depends on the two remaining install ports:
    • InstallationDownloadStatusUpdater
    • InstallationCompletionNotifier
  • InstallationCompletionHandler is the app-side implementation of the completion port. It now talks directly to UpdatesDao and UpdatesNotifier.
  • AppManager is the main shared collaborator across both enqueue and processing paths.

Layer split

  • app: facade, enqueue flow, event dispatch, update notification, and completion handling
  • data: InstallationProcessor, install models/repository, and the two remaining install ports
  • Current boundary: data only abstracts what it cannot depend on from app

Tests

Issues

https://gitlab.e.foundation/e/os/backlog/-/issues/4177

https://gitlab.e.foundation/e/os/backlog/-/issues/4165

10 commandments of code review

👪 ❤️ code review guidelines

Edited by Fahim M. Choudhury

Merge request reports

Loading