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

Commit 1a913c37 authored by Vania Desmonda's avatar Vania Desmonda Committed by Android (Google) Code Review
Browse files

Merge "Refactor education proto into 3 separate protos to allow them to be...

Merge "Refactor education proto into 3 separate protos to allow them to be triggered independently." into main
parents d1e5b595 af206d5c
Loading
Loading
Loading
Loading
+14 −14
Original line number Diff line number Diff line
@@ -82,9 +82,9 @@ class AppHandleEducationController(
    runIfEducationFeatureEnabled {
      applicationCoroutineScope.launch {
        // Central block handling the app handle's educational flow end-to-end.
        isEducationViewedFlow()
            .flatMapLatest { isEducationViewed ->
              if (isEducationViewed) {
        isAppHandleHintViewedFlow()
            .flatMapLatest { isAppHandleHintViewed ->
              if (isAppHandleHintViewed) {
                // If the education is viewed then return emptyFlow() that completes immediately.
                // This will help us to not listen to [captionHandleStateFlow] after the education
                // has been viewed already.
@@ -106,12 +106,12 @@ class AppHandleEducationController(

              showEducation(captionState, tooltipColorScheme)
              // After showing first tooltip, mark education as viewed
              appHandleEducationDatastoreRepository.updateEducationViewedTimestampMillis(true)
              appHandleEducationDatastoreRepository.updateAppHandleHintViewedTimestampMillis(true)
            }
      }

      applicationCoroutineScope.launch {
        if (isFeatureUsed()) return@launch
        if (isAppHandleHintUsed()) return@launch
        windowDecorCaptionHandleRepository.captionStateFlow
            .filter { captionState ->
              captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded
@@ -119,8 +119,8 @@ class AppHandleEducationController(
            .take(1)
            .flowOn(backgroundDispatcher)
            .collect {
              // If user expands app handle, mark user has used the feature
              appHandleEducationDatastoreRepository.updateFeatureUsedTimestampMillis(true)
              // If user expands app handle, mark user has used the app handle hint
              appHandleEducationDatastoreRepository.updateAppHandleHintUsedTimestampMillis(true)
            }
      }
    }
@@ -323,25 +323,25 @@ class AppHandleEducationController(
      }

  /**
   * Listens to the changes to [WindowingEducationProto#hasEducationViewedTimestampMillis()] in
   * Listens to the changes to [WindowingEducationProto#hasAppHandleHintViewedTimestampMillis()] in
   * datastore proto object.
   *
   * If [SHOULD_OVERRIDE_EDUCATION_CONDITIONS] is true, this flow will always emit false. That means
   * it will emit education has not been viewed yet always.
   * it will always emit app handle hint has not been viewed yet.
   */
  private fun isEducationViewedFlow(): Flow<Boolean> =
  private fun isAppHandleHintViewedFlow(): Flow<Boolean> =
      appHandleEducationDatastoreRepository.dataStoreFlow
          .map { preferences ->
            preferences.hasEducationViewedTimestampMillis() && !SHOULD_OVERRIDE_EDUCATION_CONDITIONS
            preferences.hasAppHandleHintViewedTimestampMillis() && !SHOULD_OVERRIDE_EDUCATION_CONDITIONS
          }
          .distinctUntilChanged()

  /**
   * Listens to the changes to [WindowingEducationProto#hasFeatureUsedTimestampMillis()] in
   * Listens to the changes to [WindowingEducationProto#hasAppHandleHintUsedTimestampMillis()] in
   * datastore proto object.
   */
  private suspend fun isFeatureUsed(): Boolean =
      appHandleEducationDatastoreRepository.dataStoreFlow.first().hasFeatureUsedTimestampMillis()
  private suspend fun isAppHandleHintUsed(): Boolean =
      appHandleEducationDatastoreRepository.dataStoreFlow.first().hasAppHandleHintUsedTimestampMillis()

  private fun getSize(@DimenRes resourceId: Int): Int {
    if (resourceId == Resources.ID_NULL) return 0
+6 −6
Original line number Diff line number Diff line
@@ -54,8 +54,8 @@ class AppHandleEducationFilter(
    return isFocusAppInAllowlist(focusAppPackageName) &&
        !isOtherEducationShowing() &&
        hasSufficientTimeSinceSetup() &&
        !isEducationViewedBefore(windowingEducationProto) &&
        !isFeatureUsedBefore(windowingEducationProto) &&
        !isAppHandleHintViewedBefore(windowingEducationProto) &&
        !isAppHandleHintUsedBefore(windowingEducationProto) &&
        hasMinAppUsage(windowingEducationProto, focusAppPackageName)
  }

@@ -76,11 +76,11 @@ class AppHandleEducationFilter(
          convertIntegerResourceToDuration(
              R.integer.desktop_windowing_education_required_time_since_setup_seconds)

  private fun isEducationViewedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
      windowingEducationProto.hasEducationViewedTimestampMillis()
  private fun isAppHandleHintViewedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
      windowingEducationProto.hasAppHandleHintViewedTimestampMillis()

  private fun isFeatureUsedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
      windowingEducationProto.hasFeatureUsedTimestampMillis()
  private fun isAppHandleHintUsedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
      windowingEducationProto.hasAppHandleHintUsedTimestampMillis()

  private suspend fun hasMinAppUsage(
      windowingEducationProto: WindowingEducationProto,
+12 −10
Original line number Diff line number Diff line
@@ -71,32 +71,34 @@ constructor(private val dataStore: DataStore<WindowingEducationProto>) {
  suspend fun windowingEducationProto(): WindowingEducationProto = dataStoreFlow.first()

  /**
   * Updates [WindowingEducationProto.educationViewedTimestampMillis_] field in datastore with
   * current timestamp if [isViewed] is true, if not then clears the field.
   * Updates [WindowingEducationProto.appHandleHintViewedTimestampMillis_] field
   * in datastore with current timestamp if [isViewed] is true, if not then
   * clears the field.
   */
  suspend fun updateEducationViewedTimestampMillis(isViewed: Boolean) {
  suspend fun updateAppHandleHintViewedTimestampMillis(isViewed: Boolean) {
    dataStore.updateData { preferences ->
      if (isViewed) {
        preferences
            .toBuilder()
            .setEducationViewedTimestampMillis(System.currentTimeMillis())
            .setAppHandleHintViewedTimestampMillis(System.currentTimeMillis())
            .build()
      } else {
        preferences.toBuilder().clearEducationViewedTimestampMillis().build()
        preferences.toBuilder().clearAppHandleHintViewedTimestampMillis().build()
      }
    }
  }

  /**
   * Updates [WindowingEducationProto.featureUsedTimestampMillis_] field in datastore with current
   * timestamp if [isViewed] is true, if not then clears the field.
   * Updates [WindowingEducationProto.appHandleHintUsedTimestampMillis_] field
   * in datastore with current timestamp if [isViewed] is true, if not then
   * clears the field.
   */
  suspend fun updateFeatureUsedTimestampMillis(isViewed: Boolean) {
  suspend fun updateAppHandleHintUsedTimestampMillis(isViewed: Boolean) {
    dataStore.updateData { preferences ->
      if (isViewed) {
        preferences.toBuilder().setFeatureUsedTimestampMillis(System.currentTimeMillis()).build()
        preferences.toBuilder().setAppHandleHintUsedTimestampMillis(System.currentTimeMillis()).build()
      } else {
        preferences.toBuilder().clearFeatureUsedTimestampMillis().build()
        preferences.toBuilder().clearAppHandleHintUsedTimestampMillis().build()
      }
    }
  }
+12 −2
Original line number Diff line number Diff line
@@ -22,9 +22,19 @@ option java_multiple_files = true;
// Desktop Windowing education data
message WindowingEducationProto {
  // Timestamp in milliseconds of when the education was last viewed.
  optional int64 education_viewed_timestamp_millis = 1;
  optional int64 education_viewed_timestamp_millis = 1 [deprecated=true];
  // Timestamp in milliseconds of when the feature was last used.
  optional int64 feature_used_timestamp_millis = 2;
  optional int64 feature_used_timestamp_millis = 2 [deprecated=true];

  // Timestamp in milliseconds of when the app handle hint was last viewed.
  optional int64 app_handle_hint_viewed_timestamp_millis = 5;
  // Timestamp in milliseconds of when the app handle hint was last used.
  optional int64 app_handle_hint_used_timestamp_millis = 6;
  // Timestamp in milliseconds of when the enter desktop mode hint was last viewed.
  optional int64 enter_desktop_mode_hint_viewed_timestamp_millis = 7;
  // Timestamp in milliseconds of when the exit desktop mode hint was last viewed.
  optional int64 exit_desktop_mode_hint_viewed_timestamp_millis = 8;

  oneof education_data {
    // Fields specific to app handle education
    AppHandleEducation app_handle_education = 3;
+15 −14
Original line number Diff line number Diff line
@@ -175,13 +175,13 @@ class AppHandleEducationControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
  fun init_educationViewedAlready_shouldNotCallShowEducationTooltip() =
  fun init_appHandleHintViewedAlready_shouldNotCallShowEducationTooltip() =
      testScope.runTest {
        // App handle is visible but education has been viewed before. Should not show education
        // tooltip.
        // Mark education viewed.
        // App handle is visible but app handle hint has been viewed before,
        // should not show education tooltip.
        // Mark app handle hint viewed.
        testDataStoreFlow.value =
            createWindowingEducationProto(educationViewedTimestampMillis = 123L)
            createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L)
        setShouldShowAppHandleEducation(true)

        // Simulate app handle visible.
@@ -194,13 +194,14 @@ class AppHandleEducationControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
  fun overridePrerequisite_educationViewedAlready_shouldCallShowEducationTooltip() =
  fun overridePrerequisite_appHandleHintViewedAlready_shouldCallShowEducationTooltip() =
      testScope.runTest {
        // App handle is visible but education has been viewed before. But as we are overriding
        // prerequisite conditions, we should show education tooltip.
        // Mark education viewed.
        // App handle is visible but app handle hint has been viewed before.
        // But as we are overriding prerequisite conditions, we should show app
        // handle tooltip.
        // Mark app handle hint viewed.
        testDataStoreFlow.value =
            createWindowingEducationProto(educationViewedTimestampMillis = 123L)
            createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L)
        val systemPropertiesKey =
            "persist.desktop_windowing_app_handle_education_override_conditions"
        whenever(SystemProperties.getBoolean(eq(systemPropertiesKey), anyBoolean()))
@@ -217,7 +218,7 @@ class AppHandleEducationControllerTest : ShellTestCase() {

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
  fun init_appHandleExpanded_shouldMarkFeatureViewed() =
  fun init_appHandleExpanded_shouldMarkAppHandleHintUsed() =
      testScope.runTest {
        setShouldShowAppHandleEducation(false)

@@ -226,12 +227,12 @@ class AppHandleEducationControllerTest : ShellTestCase() {
        // Wait for some time before verifying
        waitForBufferDelay()

        verify(mockDataStoreRepository, times(1)).updateFeatureUsedTimestampMillis(eq(true))
        verify(mockDataStoreRepository, times(1)).updateAppHandleHintUsedTimestampMillis(eq(true))
      }

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
  fun init_showFirstTooltip_shouldMarkEducationViewed() =
  fun init_showFirstTooltip_shouldMarkAppHandleHintViewed() =
      testScope.runTest {
        // App handle is visible. Should show education tooltip.
        setShouldShowAppHandleEducation(true)
@@ -241,7 +242,7 @@ class AppHandleEducationControllerTest : ShellTestCase() {
        // Wait for first tooltip to showup.
        waitForBufferDelay()

        verify(mockDataStoreRepository, times(1)).updateEducationViewedTimestampMillis(eq(true))
        verify(mockDataStoreRepository, times(1)).updateAppHandleHintViewedTimestampMillis(eq(true))
      }

  @Test
Loading