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

Commit df7471fb authored by Shivangi Dubey's avatar Shivangi Dubey Committed by Android (Google) Code Review
Browse files

Merge "Update App handle education datastore when specific events occurs" into main

parents d1e712d1 4a644e6a
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
@@ -95,7 +96,25 @@ class AppHandleEducationController(
              }
            }
            .flowOn(backgroundDispatcher)
            .collectLatest { captionState -> showEducation(captionState) }
            .collectLatest { captionState ->
              showEducation(captionState)
              // After showing first tooltip, mark education as viewed
              appHandleEducationDatastoreRepository.updateEducationViewedTimestampMillis(true)
            }
      }

      applicationCoroutineScope.launch {
        if (isFeatureUsed()) return@launch
        windowDecorCaptionHandleRepository.captionStateFlow
            .filter { captionState ->
              captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded
            }
            .take(1)
            .flowOn(backgroundDispatcher)
            .collect {
              // If user expands app handle, mark user has used the feature
              appHandleEducationDatastoreRepository.updateFeatureUsedTimestampMillis(true)
            }
      }
    }
  }
@@ -272,6 +291,13 @@ class AppHandleEducationController(
          .map { preferences -> preferences.hasEducationViewedTimestampMillis() }
          .distinctUntilChanged()

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

  private fun getSize(@DimenRes resourceId: Int): Int {
    if (resourceId == Resources.ID_NULL) return 0
    return context.resources.getDimensionPixelSize(resourceId)
+31 −0
Original line number Diff line number Diff line
@@ -70,6 +70,37 @@ 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.
   */
  suspend fun updateEducationViewedTimestampMillis(isViewed: Boolean) {
    dataStore.updateData { preferences ->
      if (isViewed) {
        preferences
            .toBuilder()
            .setEducationViewedTimestampMillis(System.currentTimeMillis())
            .build()
      } else {
        preferences.toBuilder().clearEducationViewedTimestampMillis().build()
      }
    }
  }

  /**
   * Updates [WindowingEducationProto.featureUsedTimestampMillis_] field in datastore with current
   * timestamp if [isViewed] is true, if not then clears the field.
   */
  suspend fun updateFeatureUsedTimestampMillis(isViewed: Boolean) {
    dataStore.updateData { preferences ->
      if (isViewed) {
        preferences.toBuilder().setFeatureUsedTimestampMillis(System.currentTimeMillis()).build()
      } else {
        preferences.toBuilder().clearFeatureUsedTimestampMillis().build()
      }
    }
  }

  /**
   * Updates [AppHandleEducation.appUsageStats] and
   * [AppHandleEducation.appUsageStatsLastUpdateTimestampMillis] fields in datastore with
+30 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
@@ -188,6 +189,35 @@ class AppHandleEducationControllerTest : ShellTestCase() {
        verify(mockTooltipController, never()).showEducationTooltip(any(), any())
      }

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

        // Simulate app handle visible and expanded.
        testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true)
        // Wait for some time before verifying
        waitForBufferDelay()

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

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
  fun init_showFirstTooltip_shouldMarkEducationViewed() =
      testScope.runTest {
        // App handle is visible. Should show education tooltip.
        setShouldShowAppHandleEducation(true)

        // Simulate app handle visible.
        testCaptionStateFlow.value = createAppHandleState()
        // Wait for first tooltip to showup.
        waitForBufferDelay()

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

  @Test
  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
  fun showWindowingImageButtonTooltip_appHandleExpanded_shouldCallShowEducationTooltipTwice() =
+18 −0
Original line number Diff line number Diff line
@@ -109,6 +109,24 @@ class AppHandleEducationDatastoreRepositoryTest {
        assertThat(result).isEqualTo(windowingEducationProto)
      }

  @Test
  fun updateEducationViewedTimestampMillis_updatesDatastoreProto() =
      runTest(StandardTestDispatcher()) {
        datastoreRepository.updateEducationViewedTimestampMillis(true)

        val result = testDatastore.data.first().hasEducationViewedTimestampMillis()
        assertThat(result).isEqualTo(true)
      }

  @Test
  fun updateFeatureUsedTimestampMillis_updatesDatastoreProto() =
      runTest(StandardTestDispatcher()) {
        datastoreRepository.updateFeatureUsedTimestampMillis(true)

        val result = testDatastore.data.first().hasFeatureUsedTimestampMillis()
        assertThat(result).isEqualTo(true)
      }

  companion object {
    private const val APP_HANDLE_EDUCATION_DATASTORE_TEST_FILE = "app_handle_education_test.pb"
  }