diff options
37 files changed, 769 insertions, 242 deletions
| diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java index 8baa55f8e377..6e2e1009fd40 100644 --- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -74,8 +74,8 @@ final class ChildContentCaptureSession extends ContentCaptureSession {      }      @Override -    void flush(@FlushReason int reason) { -        mParent.flush(reason); +    void internalFlush(@FlushReason int reason) { +        mParent.internalFlush(reason);      }      @Override diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 3f3484d5a527..b7a77d701045 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -663,7 +663,7 @@ public final class ContentCaptureManager {      @UiThread      public void flush(@FlushReason int reason) {          if (mOptions.lite) return; -        getMainContentCaptureSession().flush(reason); +        getMainContentCaptureSession().internalFlush(reason);      }      /** diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 6bb2975d9cf1..791a6f4254ec 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -342,7 +342,7 @@ public abstract class ContentCaptureSession implements AutoCloseable {      /**       * Flushes the buffered events to the service.       */ -    abstract void flush(@FlushReason int reason); +    abstract void internalFlush(@FlushReason int reason);      /**       * Sets the {@link ContentCaptureContext} associated with the session. diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index eddfc42da9bd..29cae857098d 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -375,7 +375,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {      void onDestroy() {          clearAndRunOnContentCaptureThread(() -> {              try { -                flush(FLUSH_REASON_SESSION_FINISHED); +                internalFlush(FLUSH_REASON_SESSION_FINISHED);              } finally {                  destroySession();              } @@ -623,7 +623,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {                  flushReason = forceFlush ? FLUSH_REASON_FORCE_FLUSH : FLUSH_REASON_FULL;          } -        flush(flushReason); +        internalFlush(flushReason);      }      private boolean hasStarted() { @@ -687,15 +687,18 @@ public final class MainContentCaptureSession extends ContentCaptureSession {              if (sVerbose) Log.v(TAG, "Nothing to flush");              return;          } -        flush(reason); +        internalFlush(reason);      } -    /** @hide */ +    /** +     * Internal API to flush the buffered events to the service. +     * +     * Do not confuse this with the public API {@link #flush()}. +     * +     * @hide */      @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)      @Override -    public void flush(@FlushReason int reason) { -        // TODO: b/380381249 renaming the internal APIs to prevent confusions between this and the -        // public API. +    public void internalFlush(@FlushReason int reason) {          runOnContentCaptureThread(() -> flushImpl(reason));      } diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml index 44a5df9b60be..c43975e4ad3c 100644 --- a/core/res/res/layout/preference_list_fragment.xml +++ b/core/res/res/layout/preference_list_fragment.xml @@ -19,7 +19,6 @@  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:orientation="vertical" -    android:fitsSystemWindows="true"      android:layout_height="match_parent"      android:layout_width="match_parent"      android:background="@android:color/transparent" diff --git a/core/res/res/layout/preference_list_fragment_material.xml b/core/res/res/layout/preference_list_fragment_material.xml index 4df76029e606..db2fe7d038e0 100644 --- a/core/res/res/layout/preference_list_fragment_material.xml +++ b/core/res/res/layout/preference_list_fragment_material.xml @@ -19,7 +19,6 @@  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:orientation="vertical" -    android:fitsSystemWindows="true"      android:layout_height="match_parent"      android:layout_width="match_parent"      android:background="@android:color/transparent" diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java index f87b6994900f..ee8d428d8370 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java @@ -224,7 +224,7 @@ public class ContentCaptureSessionTest {          }          @Override -        void flush(int reason) { +        void internalFlush(int reason) {              throw new UnsupportedOperationException("should not have been called");          } diff --git a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java index 4a5123ec0663..a1d7f87614e4 100644 --- a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java @@ -263,7 +263,7 @@ public class MainContentCaptureSessionTest {          session.mEvents = new ArrayList<>(Arrays.asList(EVENT));          session.mDirectServiceInterface = mMockContentCaptureDirectManager; -        session.flush(REASON); +        session.internalFlush(REASON);          mTestableLooper.processAllMessages();          verifyZeroInteractions(mMockContentProtectionEventProcessor); @@ -280,7 +280,7 @@ public class MainContentCaptureSessionTest {          session.mEvents = new ArrayList<>(Arrays.asList(EVENT));          session.mDirectServiceInterface = mMockContentCaptureDirectManager; -        session.flush(REASON); +        session.internalFlush(REASON);          mTestableLooper.processAllMessages();          verifyZeroInteractions(mMockContentProtectionEventProcessor); @@ -298,7 +298,7 @@ public class MainContentCaptureSessionTest {          session.mEvents = new ArrayList<>(Arrays.asList(EVENT));          session.mDirectServiceInterface = mMockContentCaptureDirectManager; -        session.flush(REASON); +        session.internalFlush(REASON);          mTestableLooper.processAllMessages();          verifyZeroInteractions(mMockContentProtectionEventProcessor); @@ -316,7 +316,7 @@ public class MainContentCaptureSessionTest {          session.mEvents = new ArrayList<>(Arrays.asList(EVENT));          session.mDirectServiceInterface = mMockContentCaptureDirectManager; -        session.flush(REASON); +        session.internalFlush(REASON);          mTestableLooper.processAllMessages();          verifyZeroInteractions(mMockContentProtectionEventProcessor); @@ -544,7 +544,7 @@ public class MainContentCaptureSessionTest {          session.mContentCaptureHandler = null;          session.mDirectServiceInterface = null; -        session.flush(REASON); +        session.internalFlush(REASON);          assertThat(session.mEvents).hasSize(1);          assertThat(session.mEventProcessQueue).isEmpty(); diff --git a/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml index e5fe1b5431eb..83a3959ee2f9 100644 --- a/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml +++ b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_maximize_button_dark.xml @@ -22,5 +22,6 @@      android:viewportWidth="960">      <path          android:fillColor="@android:color/black" -        android:pathData="M160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM160,720L800,720Q800,720 800,720Q800,720 800,720L800,320L160,320L160,720Q160,720 160,720Q160,720 160,720Z"/> +        android:pathData="M 244.79 796.408 C 222.79 796.408 203.79 788.74 187.79 773.408 C 172.457 757.408 164.79 738.408 164.79 716.408 L 164.79 236.408 C 164.79 214.408 172.457 195.741 187.79 180.408 C 203.79 164.408 222.79 156.408 244.79 156.408 L 724.79 156.408 C 746.79 156.408 765.458 164.408 780.79 180.408 C 796.79 195.741 804.79 214.408 804.79 236.408 L 804.79 716.408 C 804.79 738.408 796.79 757.408 780.79 773.408 C 765.458 788.74 746.79 796.408 724.79 796.408 Z M 244.79 716.408 L 724.79 716.408 L 724.79 236.408 L 244.79 236.408 Z M 244.79 236.408 L 244.79 716.408 Z" +        />  </vector>
\ No newline at end of file diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt index bd5d17cb2468..b82c554ea26a 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt @@ -45,7 +45,7 @@ interface PreferenceScreenBinding : PreferenceBinding {                      context.getString(screenTitle)                  } else {                      screenMetadata.getScreenTitle(context) -                        ?: (this as? PreferenceTitleProvider)?.getTitle(context) +                        ?: (screenMetadata as? PreferenceTitleProvider)?.getTitle(context)                  }          }      } diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt index e237a6a4cf14..ffe181d0c350 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt @@ -21,6 +21,7 @@ import android.content.Intent  import android.os.Bundle  import android.util.Log  import androidx.annotation.XmlRes +import androidx.lifecycle.Lifecycle  import androidx.preference.PreferenceScreen  import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_KEY  import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider @@ -38,6 +39,11 @@ open class PreferenceFragment :          preferenceScreen = createPreferenceScreen()      } +    override fun setPreferenceScreen(preferenceScreen: PreferenceScreen?) { +        super.setPreferenceScreen(preferenceScreen) +        updateActivityTitle() +    } +      fun createPreferenceScreen(): PreferenceScreen? =          createPreferenceScreen(PreferenceScreenFactory(this)) @@ -102,9 +108,19 @@ open class PreferenceFragment :      override fun onResume() {          super.onResume() +        // Even when activity has several fragments with preference screen, this will keep activity +        // title in sync when fragment manager pops back stack. +        updateActivityTitle()          preferenceScreenBindingHelper?.onResume()      } +    internal fun updateActivityTitle() { +        if (!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return +        val activity = activity ?: return +        val title = preferenceScreen?.title ?: return +        if (activity.title != title) activity.title = title +    } +      override fun onPause() {          preferenceScreenBindingHelper?.onPause()          super.onPause() diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt index 7492c2d0aaf2..4a6a589cd3c9 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt @@ -52,7 +52,7 @@ import com.google.common.collect.ImmutableMultimap   */  class PreferenceScreenBindingHelper(      context: Context, -    fragment: PreferenceFragment, +    private val fragment: PreferenceFragment,      private val preferenceBindingFactory: PreferenceBindingFactory,      private val preferenceScreen: PreferenceScreen,      private val preferenceHierarchy: PreferenceHierarchy, @@ -156,7 +156,9 @@ class PreferenceScreenBindingHelper(          // bind preference to update UI          preferenceScreen.findPreference<Preference>(key)?.let { -            preferences[key]?.let { node -> preferenceBindingFactory.bind(it, node) } +            val node = preferences[key] ?: return@let +            preferenceBindingFactory.bind(it, node) +            if (it == preferenceScreen) fragment.updateActivityTitle()          }          // check reason to avoid potential infinite loop diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml index 2776544e2948..7d7bec14ed78 100644 --- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml +++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml @@ -48,6 +48,7 @@          android:layout_height="wrap_content"          app:layout_constraintTop_toBottomOf="@android:id/title"          app:layout_constraintStart_toStartOf="parent" +        android:paddingTop="@dimen/settingslib_expressive_space_extrasmall6"          android:textAlignment="viewStart"          android:clickable="true"          android:visibility="gone" diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt index 56a4ed078670..b0af8b180cce 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt @@ -343,7 +343,7 @@ class CallChipViewModelTest : SysuiTestCase() {              repo.setOngoingCallState(inCallModel(startTimeMs = 1000, intent = null)) -            assertThat((latest as OngoingActivityChipModel.Shown).onClickListener).isNull() +            assertThat((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy).isNull()          }      @Test @@ -353,7 +353,7 @@ class CallChipViewModelTest : SysuiTestCase() {              val pendingIntent = mock<PendingIntent>()              repo.setOngoingCallState(inCallModel(startTimeMs = 1000, intent = pendingIntent)) -            val clickListener = (latest as OngoingActivityChipModel.Shown).onClickListener +            val clickListener = (latest as OngoingActivityChipModel.Shown).onClickListenerLegacy              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -370,7 +370,8 @@ class CallChipViewModelTest : SysuiTestCase() {              val pendingIntent = mock<PendingIntent>()              repo.setOngoingCallState(inCallModel(startTimeMs = 0, intent = pendingIntent)) -            val clickListener = (latest as OngoingActivityChipModel.Shown).onClickListener +            val clickListener = (latest as OngoingActivityChipModel.Shown).onClickListenerLegacy +              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt index c511c433d92d..fcf8c834dc12 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt @@ -17,6 +17,7 @@  package com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel  import android.content.DialogInterface +import android.platform.test.annotations.DisableFlags  import android.platform.test.annotations.EnableFlags  import android.view.View  import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -25,6 +26,7 @@ import com.android.internal.jank.Cuj  import com.android.systemui.Flags.FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.DialogCuj +import com.android.systemui.animation.Expandable  import com.android.systemui.animation.mockDialogTransitionAnimator  import com.android.systemui.common.shared.model.ContentDescription  import com.android.systemui.common.shared.model.Icon @@ -46,8 +48,10 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel  import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel  import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog +import com.android.systemui.statusbar.core.StatusBarRootModernization  import com.android.systemui.statusbar.phone.SystemUIDialog  import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory +import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization  import com.android.systemui.statusbar.policy.CastDevice  import com.android.systemui.util.time.fakeSystemClock  import com.google.common.truth.Truth.assertThat @@ -84,6 +88,8 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {                  )                  .thenReturn(chipBackgroundView)          } +    private val mockExpandable: Expandable = +        mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) }      private val underTest = kosmos.castToOtherDeviceChipViewModel @@ -263,7 +269,13 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {              // WHEN the stop action on the dialog is clicked              val dialogStopAction = -                getStopActionFromDialog(latest, chipView, mockScreenCastDialog, kosmos) +                getStopActionFromDialog( +                    latest, +                    chipView, +                    mockExpandable, +                    mockScreenCastDialog, +                    kosmos, +                )              dialogStopAction.onClick(mock<DialogInterface>(), 0)              // THEN the chip is immediately hidden... @@ -296,7 +308,13 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {              // WHEN the stop action on the dialog is clicked              val dialogStopAction = -                getStopActionFromDialog(latest, chipView, mockGenericCastDialog, kosmos) +                getStopActionFromDialog( +                    latest, +                    chipView, +                    mockExpandable, +                    mockGenericCastDialog, +                    kosmos, +                )              dialogStopAction.onClick(mock<DialogInterface>(), 0)              // THEN the chip is immediately hidden... @@ -416,13 +434,14 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_projectionStateEntireScreen_clickListenerShowsScreenCastDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip)              mediaProjectionRepo.mediaProjectionState.value =                  MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -431,6 +450,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_projectionStateSingleTask_clickListenerShowsScreenCastDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip) @@ -442,7 +462,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {                      createTask(taskId = 1),                  ) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -451,6 +471,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_routerStateCasting_clickListenerShowsGenericCastDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip) @@ -466,7 +487,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {                      )                  ) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -480,13 +501,14 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_projectionStateCasting_clickListenerHasCuj() =          testScope.runTest {              val latest by collectLastValue(underTest.chip)              mediaProjectionRepo.mediaProjectionState.value =                  MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              clickListener!!.onClick(chipView)              val cujCaptor = argumentCaptor<DialogCuj>() @@ -499,6 +521,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_routerStateCasting_clickListenerHasCuj() =          testScope.runTest {              val latest by collectLastValue(underTest.chip) @@ -514,7 +537,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {                      )                  ) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              clickListener!!.onClick(chipView)              val cujCaptor = argumentCaptor<DialogCuj>() @@ -525,4 +548,103 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() {                  .isEqualTo(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP)              assertThat(cujCaptor.firstValue.tag).contains("Cast")          } + +    @Test +    @EnableFlags(StatusBarChipsModernization.FLAG_NAME) +    fun chip_routerStateCasting_hasClickBehavior() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) + +            mediaRouterRepo.castDevices.value = +                listOf( +                    CastDevice( +                        state = CastDevice.CastState.Connected, +                        id = "id", +                        name = "name", +                        description = "desc", +                        origin = CastDevice.CastOrigin.MediaRouter, +                    ) +                ) + +            assertThat((latest as OngoingActivityChipModel.Shown).clickBehavior) +                .isInstanceOf(OngoingActivityChipModel.ClickBehavior.ExpandAction::class.java) +        } + +    @Test +    @EnableFlags(StatusBarChipsModernization.FLAG_NAME) +    fun chip_projectionStateCasting_hasClickBehavior() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) + +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE) + +            assertThat((latest as OngoingActivityChipModel.Shown).clickBehavior) +                .isInstanceOf(OngoingActivityChipModel.ClickBehavior.ExpandAction::class.java) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_projectionStateEntireScreen_clickBehaviorShowsScreenCastDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE) + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) +            expandAction.onClick(mockExpandable) + +            verify(kosmos.mockDialogTransitionAnimator) +                .show(eq(mockScreenCastDialog), any(), anyBoolean()) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_projectionStateSingleTask_clickBehaviorShowsScreenCastDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) + +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.SingleTask( +                    CAST_TO_OTHER_DEVICES_PACKAGE, +                    hostDeviceName = null, +                    createTask(taskId = 1), +                ) + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) +            expandAction.onClick(mockExpandable) + +            verify(kosmos.mockDialogTransitionAnimator) +                .show(eq(mockScreenCastDialog), any(), anyBoolean()) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_routerStateCasting_clickBehaviorShowsGenericCastDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) + +            mediaRouterRepo.castDevices.value = +                listOf( +                    CastDevice( +                        state = CastDevice.CastState.Connected, +                        id = "id", +                        name = "name", +                        description = "desc", +                        origin = CastDevice.CastOrigin.MediaRouter, +                    ) +                ) + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) +            expandAction.onClick(mockExpandable) + +            verify(kosmos.mockDialogTransitionAnimator) +                .show(eq(mockGenericCastDialog), any(), anyBoolean()) +        }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt index 902db5e10589..eec23d3ffb1a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt @@ -650,7 +650,7 @@ class NotifChipsViewModelTest : SysuiTestCase() {              )              val chip = latest!![0] -            chip.onClickListener!!.onClick(mock<View>()) +            chip.onClickListenerLegacy!!.onClick(mock<View>())              assertThat(latestChipTap).isEqualTo("clickTest")          } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt index 48d8add6b33a..1f82dcd9c308 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt @@ -17,12 +17,15 @@  package com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel  import android.content.DialogInterface +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags  import android.view.View  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.jank.Cuj  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.DialogCuj +import com.android.systemui.animation.Expandable  import com.android.systemui.animation.mockDialogTransitionAnimator  import com.android.systemui.common.shared.model.Icon  import com.android.systemui.coroutines.collectLastValue @@ -41,8 +44,10 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel  import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel  import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog +import com.android.systemui.statusbar.core.StatusBarRootModernization  import com.android.systemui.statusbar.phone.SystemUIDialog  import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory +import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization  import com.android.systemui.testKosmos  import com.android.systemui.util.time.fakeSystemClock  import com.google.common.truth.Truth.assertThat @@ -77,6 +82,8 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {                  )                  .thenReturn(chipBackgroundView)          } +    private val mockExpandable: Expandable = +        mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) }      private val underTest = kosmos.screenRecordChipViewModel @@ -106,7 +113,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {              assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Countdown::class.java)              assertThat((latest as OngoingActivityChipModel.Shown).icon).isNull() -            assertThat((latest as OngoingActivityChipModel.Shown).onClickListener).isNull() +            assertThat((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy).isNull()          }      // The millis we typically get from [ScreenRecordRepository] are around 2995, 1995, and 995. @@ -177,7 +184,13 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {              // WHEN the stop action on the dialog is clicked              val dialogStopAction = -                getStopActionFromDialog(latest, chipView, mockSystemUIDialog, kosmos) +                getStopActionFromDialog( +                    latest, +                    chipView, +                    mockExpandable, +                    mockSystemUIDialog, +                    kosmos, +                )              dialogStopAction.onClick(mock<DialogInterface>(), 0)              // THEN both the screen record chip and the share-to-app chip are immediately hidden... @@ -263,13 +276,14 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_notProjecting_clickListenerShowsDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip)              screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording              mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.NotProjecting -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -279,6 +293,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_projectingEntireScreen_clickListenerShowsDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip) @@ -286,7 +301,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {              mediaProjectionRepo.mediaProjectionState.value =                  MediaProjectionState.Projecting.EntireScreen("host.package") -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -296,6 +311,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_projectingSingleTask_clickListenerShowsDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip) @@ -307,7 +323,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {                      FakeActivityTaskManager.createTask(taskId = 1),                  ) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -317,22 +333,85 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() {          }      @Test -    fun chip_clickListenerHasCuj() = +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME) +    fun chip_clickListenerHasCujLegacy() =          testScope.runTest {              val latest by collectLastValue(underTest.chip)              screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording              mediaProjectionRepo.mediaProjectionState.value =                  MediaProjectionState.Projecting.EntireScreen("host.package") -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              clickListener!!.onClick(chipView)              val cujCaptor = argumentCaptor<DialogCuj>()              verify(kosmos.mockDialogTransitionAnimator)                  .showFromView(any(), any(), cujCaptor.capture(), anyBoolean()) -              assertThat(cujCaptor.firstValue.cujType)                  .isEqualTo(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP)              assertThat(cujCaptor.firstValue.tag).contains("Screen record")          } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_recordingState_hasClickBehavior() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording +            assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java) +            assertThat((latest as OngoingActivityChipModel.Shown).clickBehavior) +                .isInstanceOf(OngoingActivityChipModel.ClickBehavior.ExpandAction::class.java) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_notProjecting_expandActionBehaviorShowsDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording +            mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.NotProjecting + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) + +            expandAction.onClick(mockExpandable) +            verify(kosmos.mockDialogTransitionAnimator).show(any(), any(), anyBoolean()) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_projectingEntireScreen_expandActionBehaviorShowsDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) + +            expandAction.onClick(mockExpandable) +            verify(kosmos.mockDialogTransitionAnimator).show(any(), any(), anyBoolean()) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_projectingSingleTask_expandActionBehaviorShowsDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.SingleTask( +                    "host.package", +                    hostDeviceName = null, +                    FakeActivityTaskManager.createTask(taskId = 1), +                ) + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) + +            expandAction.onClick(mockExpandable) +            verify(kosmos.mockDialogTransitionAnimator).show(any(), any(), anyBoolean()) +        }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt index b3dec2eaa1c6..36fc5aa16407 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt @@ -17,6 +17,7 @@  package com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel  import android.content.DialogInterface +import android.platform.test.annotations.DisableFlags  import android.platform.test.annotations.EnableFlags  import android.view.View  import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -25,6 +26,7 @@ import com.android.internal.jank.Cuj  import com.android.systemui.Flags.FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.DialogCuj +import com.android.systemui.animation.Expandable  import com.android.systemui.animation.mockDialogTransitionAnimator  import com.android.systemui.common.shared.model.ContentDescription  import com.android.systemui.common.shared.model.Icon @@ -45,8 +47,10 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel  import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel  import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog +import com.android.systemui.statusbar.core.StatusBarRootModernization  import com.android.systemui.statusbar.phone.SystemUIDialog  import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory +import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization  import com.android.systemui.util.time.fakeSystemClock  import com.google.common.truth.Truth.assertThat  import kotlin.test.Test @@ -81,6 +85,8 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {                  )                  .thenReturn(chipBackgroundView)          } +    private val mockExpandable: Expandable = +        mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) }      private val underTest = kosmos.shareToAppChipViewModel @@ -215,7 +221,13 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {              // WHEN the stop action on the dialog is clicked              val dialogStopAction = -                getStopActionFromDialog(latest, chipView, mockScreenShareDialog, kosmos) +                getStopActionFromDialog( +                    latest, +                    chipView, +                    mockExpandable, +                    mockScreenShareDialog, +                    kosmos, +                )              dialogStopAction.onClick(mock<DialogInterface>(), 0)              // THEN the chip is immediately hidden... @@ -268,13 +280,14 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {      @Test      @EnableFlags(FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP) +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_noScreen_clickListenerShowsGenericShareDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip)              mediaProjectionRepo.mediaProjectionState.value =                  MediaProjectionState.Projecting.NoScreen(NORMAL_PACKAGE) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -288,13 +301,14 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_entireScreen_clickListenerShowsScreenShareDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip)              mediaProjectionRepo.mediaProjectionState.value =                  MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -308,6 +322,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_singleTask_clickListenerShowsScreenShareDialog() =          testScope.runTest {              val latest by collectLastValue(underTest.chip) @@ -318,7 +333,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {                      createTask(taskId = 1),                  ) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              assertThat(clickListener).isNotNull()              clickListener!!.onClick(chipView) @@ -332,6 +347,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun chip_clickListenerHasCuj() =          testScope.runTest {              val latest by collectLastValue(underTest.chip) @@ -342,7 +358,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {                      createTask(taskId = 1),                  ) -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) +            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy)              clickListener!!.onClick(chipView)              val cujCaptor = argumentCaptor<DialogCuj>() @@ -353,4 +369,101 @@ class ShareToAppChipViewModelTest : SysuiTestCase() {                  .isEqualTo(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP)              assertThat(cujCaptor.firstValue.tag).contains("Share")          } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_noScreen_hasClickBehavior() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.NoScreen(NORMAL_PACKAGE) + +            assertThat((latest as OngoingActivityChipModel.Shown).clickBehavior) +                .isInstanceOf(OngoingActivityChipModel.ClickBehavior.ExpandAction::class.java) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_entireScreen_hasClickBehavior() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE) + +            assertThat((latest as OngoingActivityChipModel.Shown).clickBehavior) +                .isInstanceOf(OngoingActivityChipModel.ClickBehavior.ExpandAction::class.java) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_singleTask_hasClickBehavior() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.SingleTask( +                    NORMAL_PACKAGE, +                    hostDeviceName = null, +                    createTask(taskId = 1), +                ) + +            assertThat((latest as OngoingActivityChipModel.Shown).clickBehavior) +                .isInstanceOf(OngoingActivityChipModel.ClickBehavior.ExpandAction::class.java) +        } + +    @Test +    @EnableFlags( +        FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP, +        StatusBarRootModernization.FLAG_NAME, +        StatusBarChipsModernization.FLAG_NAME, +    ) +    fun chip_noScreen_clickBehaviorShowsGenericShareDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.NoScreen(NORMAL_PACKAGE) + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) +            expandAction.onClick(mockExpandable) +            verify(kosmos.mockDialogTransitionAnimator) +                .show(eq(mockGenericShareDialog), any(), any()) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_entireScreen_clickBehaviorShowsScreenShareDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE) + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) +            expandAction.onClick(mockExpandable) +            verify(kosmos.mockDialogTransitionAnimator) +                .show(eq(mockScreenShareDialog), any(), any()) +        } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun chip_singleTask_clickBehaviorShowsScreenShareDialog() = +        testScope.runTest { +            val latest by collectLastValue(underTest.chip) +            mediaProjectionRepo.mediaProjectionState.value = +                MediaProjectionState.Projecting.SingleTask( +                    NORMAL_PACKAGE, +                    hostDeviceName = null, +                    createTask(taskId = 1), +                ) + +            val expandAction = +                ((latest as OngoingActivityChipModel.Shown).clickBehavior +                    as OngoingActivityChipModel.ClickBehavior.ExpandAction) +            expandAction.onClick(mockExpandable) + +            verify(kosmos.mockDialogTransitionAnimator) +                .show(eq(mockScreenShareDialog), any(), any()) +        }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt index 8d4c68de8c79..d099e70c9bc5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt @@ -57,7 +57,8 @@ class ChipTransitionHelperTest : SysuiTestCase() {                      icon = createIcon(R.drawable.ic_cake),                      colors = ColorsModel.Themed,                      startTimeMs = 100L, -                    onClickListener = null, +                    onClickListenerLegacy = null, +                    clickBehavior = OngoingActivityChipModel.ClickBehavior.None,                  )              inputChipFlow.value = newChip @@ -68,7 +69,8 @@ class ChipTransitionHelperTest : SysuiTestCase() {                  OngoingActivityChipModel.Shown.IconOnly(                      icon = createIcon(R.drawable.ic_hotspot),                      colors = ColorsModel.Themed, -                    onClickListener = null, +                    onClickListenerLegacy = null, +                    clickBehavior = OngoingActivityChipModel.ClickBehavior.None,                  )              inputChipFlow.value = newerChip @@ -89,7 +91,8 @@ class ChipTransitionHelperTest : SysuiTestCase() {                      icon = createIcon(R.drawable.ic_cake),                      colors = ColorsModel.Themed,                      startTimeMs = 100L, -                    onClickListener = null, +                    onClickListenerLegacy = null, +                    clickBehavior = OngoingActivityChipModel.ClickBehavior.None,                  )              inputChipFlow.value = shownChip @@ -129,7 +132,8 @@ class ChipTransitionHelperTest : SysuiTestCase() {                      icon = createIcon(R.drawable.ic_cake),                      colors = ColorsModel.Themed,                      startTimeMs = 100L, -                    onClickListener = null, +                    onClickListenerLegacy = null, +                    clickBehavior = OngoingActivityChipModel.ClickBehavior.None,                  )              inputChipFlow.value = shownChip diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt index e3510f5ce280..fc3af11c30b3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt @@ -16,6 +16,8 @@  package com.android.systemui.statusbar.chips.ui.viewmodel +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags  import android.view.View  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest @@ -23,14 +25,19 @@ import com.android.internal.jank.Cuj  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.DialogCuj  import com.android.systemui.animation.DialogTransitionAnimator +import com.android.systemui.animation.Expandable  import com.android.systemui.log.logcatLogBuffer  import com.android.systemui.res.R  import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer +import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener +import com.android.systemui.statusbar.core.StatusBarRootModernization  import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization  import kotlin.test.Test  import org.junit.runner.RunWith  import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.kotlin.any  import org.mockito.kotlin.eq  import org.mockito.kotlin.mock  import org.mockito.kotlin.verify @@ -53,8 +60,11 @@ class OngoingActivityChipViewModelTest : SysuiTestCase() {                  )                  .thenReturn(chipBackgroundView)          } +    private val mockExpandable: Expandable = +        mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) }      @Test +    @DisableFlags(StatusBarChipsModernization.FLAG_NAME)      fun createDialogLaunchOnClickListener_showsDialogOnClick() {          val cuj = DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Test")          val clickListener = @@ -68,11 +78,23 @@ class OngoingActivityChipViewModelTest : SysuiTestCase() {          clickListener.onClick(chipView)          verify(dialogTransitionAnimator) -            .showFromView( -                eq(mockSystemUIDialog), -                eq(chipBackgroundView), -                eq(cuj), -                anyBoolean(), +            .showFromView(eq(mockSystemUIDialog), eq(chipBackgroundView), eq(cuj), anyBoolean()) +    } + +    @Test +    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) +    fun createDialogLaunchOnClickCallback_showsDialogOnClick() { +        val cuj = DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Test") +        val clickCallback = +            createDialogLaunchOnClickCallback( +                dialogDelegate, +                dialogTransitionAnimator, +                cuj, +                logcatLogBuffer("OngoingActivityChipViewModelTest"), +                "tag",              ) + +        clickCallback.invoke(mockExpandable) +        verify(dialogTransitionAnimator).show(eq(mockSystemUIDialog), any(), anyBoolean())      }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt index 42358cce59a2..a4b6a841d61b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt @@ -26,6 +26,7 @@ import android.view.View  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.Expandable  import com.android.systemui.common.shared.model.Icon  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.kosmos.Kosmos @@ -44,6 +45,7 @@ import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer  import com.android.systemui.statusbar.core.StatusBarConnectedDisplays  import com.android.systemui.statusbar.phone.SystemUIDialog  import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory +import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization  import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository  import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel  import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel @@ -91,6 +93,8 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() {                  )                  .thenReturn(chipBackgroundView)          } +    private val mockExpandable: Expandable = +        mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) }      private val underTest = kosmos.ongoingActivityChipsViewModel @@ -294,7 +298,13 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() {              // WHEN screen record gets stopped via dialog              val dialogStopAction = -                getStopActionFromDialog(latest, chipView, mockSystemUIDialog, kosmos) +                getStopActionFromDialog( +                    latest, +                    chipView, +                    mockExpandable, +                    mockSystemUIDialog, +                    kosmos, +                )              dialogStopAction.onClick(mock<DialogInterface>(), 0)              // THEN the chip is immediately hidden with no animation @@ -315,7 +325,13 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() {              // WHEN media projection gets stopped via dialog              val dialogStopAction = -                getStopActionFromDialog(latest, chipView, mockSystemUIDialog, kosmos) +                getStopActionFromDialog( +                    latest, +                    chipView, +                    mockExpandable, +                    mockSystemUIDialog, +                    kosmos, +                )              dialogStopAction.onClick(mock<DialogInterface>(), 0)              // THEN the chip is immediately hidden with no animation @@ -330,6 +346,7 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() {          fun getStopActionFromDialog(              latest: OngoingActivityChipModel?,              chipView: View, +            expandable: Expandable,              dialog: SystemUIDialog,              kosmos: Kosmos,          ): DialogInterface.OnClickListener { @@ -349,9 +366,17 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() {                  .create(any<SystemUIDialog.Delegate>())              whenever(kosmos.packageManager.getApplicationInfo(eq(NORMAL_PACKAGE), any<Int>()))                  .thenThrow(PackageManager.NameNotFoundException()) -            // Click the chip so that we open the dialog and we fill in [dialogStopAction] -            val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener) -            clickListener!!.onClick(chipView) + +            if (StatusBarChipsModernization.isEnabled) { +                val clickBehavior = (latest as OngoingActivityChipModel.Shown).clickBehavior +                (clickBehavior as OngoingActivityChipModel.ClickBehavior.ExpandAction).onClick( +                    expandable +                ) +            } else { +                val clickListener = +                    ((latest as OngoingActivityChipModel.Shown).onClickListenerLegacy) +                clickListener!!.onClick(chipView) +            }              return dialogStopAction          } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt index 0f42f29e76ee..28f360108e50 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt @@ -25,6 +25,7 @@ import android.view.View  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.Expandable  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.kosmos.testScope  import com.android.systemui.kosmos.useUnconfinedTestDispatcher @@ -104,6 +105,8 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {                  )                  .thenReturn(chipBackgroundView)          } +    private val mockExpandable: Expandable = +        mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) }      private val underTest by lazy { kosmos.ongoingActivityChipsViewModel } @@ -679,7 +682,13 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {              // WHEN screen record gets stopped via dialog              val dialogStopAction = -                getStopActionFromDialog(latest, chipView, mockSystemUIDialog, kosmos) +                getStopActionFromDialog( +                    latest, +                    chipView, +                    mockExpandable, +                    mockSystemUIDialog, +                    kosmos, +                )              dialogStopAction.onClick(mock<DialogInterface>(), 0)              // THEN the chip is immediately hidden with no animation @@ -700,7 +709,13 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {              // WHEN media projection gets stopped via dialog              val dialogStopAction = -                getStopActionFromDialog(latest, chipView, mockSystemUIDialog, kosmos) +                getStopActionFromDialog( +                    latest, +                    chipView, +                    mockExpandable, +                    mockSystemUIDialog, +                    kosmos, +                )              dialogStopAction.onClick(mock<DialogInterface>(), 0)              // THEN the chip is immediately hidden with no animation diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt index 4fb8f724c971..108d737e7658 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt @@ -92,7 +92,10 @@ constructor(                              OngoingActivityChipModel.Shown.IconOnly(                                  icon = icon,                                  colors = colors, -                                getOnClickListener(state), +                                onClickListenerLegacy = getOnClickListener(state), +                                // TODO(b/372657935): Add click support for the call chip when +                                // StatusBarChipModernization is enabled. +                                clickBehavior = OngoingActivityChipModel.ClickBehavior.None,                              )                          } else {                              val startTimeInElapsedRealtime = @@ -102,7 +105,10 @@ constructor(                                  icon = icon,                                  colors = colors,                                  startTimeMs = startTimeInElapsedRealtime, -                                getOnClickListener(state), +                                onClickListenerLegacy = getOnClickListener(state), +                                // TODO(b/372657935): Add click support for the call chip when +                                // StatusBarChipModernization is enabled. +                                clickBehavior = OngoingActivityChipModel.ClickBehavior.None,                              )                          }                      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt index 3422337523f9..baa8eec5f767 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt @@ -41,6 +41,7 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel  import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel  import com.android.systemui.statusbar.chips.ui.viewmodel.ChipTransitionHelper  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel +import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener  import com.android.systemui.util.time.SystemClock  import javax.inject.Inject @@ -204,13 +205,25 @@ constructor(              colors = ColorsModel.Red,              // TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.              startTimeMs = systemClock.elapsedRealtime(), -            createDialogLaunchOnClickListener( -                createCastScreenToOtherDeviceDialogDelegate(state), -                dialogTransitionAnimator, -                DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Cast to other device"), -                logger, -                TAG, -            ), +            onClickListenerLegacy = +                createDialogLaunchOnClickListener( +                    createCastScreenToOtherDeviceDialogDelegate(state), +                    dialogTransitionAnimator, +                    DIALOG_CUJ, +                    logger, +                    TAG, +                ), +            clickBehavior = +                OngoingActivityChipModel.ClickBehavior.ExpandAction( +                    onClick = +                        createDialogLaunchOnClickCallback( +                            createCastScreenToOtherDeviceDialogDelegate(state), +                            dialogTransitionAnimator, +                            DIALOG_CUJ, +                            logger, +                            TAG, +                        ) +                ),          )      } @@ -225,16 +238,24 @@ constructor(                      )                  ),              colors = ColorsModel.Red, -            createDialogLaunchOnClickListener( -                createGenericCastToOtherDeviceDialogDelegate(deviceName), -                dialogTransitionAnimator, -                DialogCuj( -                    Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, -                    tag = "Cast to other device audio only", +            onClickListenerLegacy = +                createDialogLaunchOnClickListener( +                    createGenericCastToOtherDeviceDialogDelegate(deviceName), +                    dialogTransitionAnimator, +                    DIALOG_CUJ_AUDIO_ONLY, +                    logger, +                    TAG, +                ), +            clickBehavior = +                OngoingActivityChipModel.ClickBehavior.ExpandAction( +                    createDialogLaunchOnClickCallback( +                        createGenericCastToOtherDeviceDialogDelegate(deviceName), +                        dialogTransitionAnimator, +                        DIALOG_CUJ_AUDIO_ONLY, +                        logger, +                        TAG, +                    )                  ), -                logger, -                TAG, -            ),          )      } @@ -256,6 +277,13 @@ constructor(      companion object {          @DrawableRes val CAST_TO_OTHER_DEVICE_ICON = R.drawable.ic_cast_connected +        private val DIALOG_CUJ = +            DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Cast to other device") +        private val DIALOG_CUJ_AUDIO_ONLY = +            DialogCuj( +                Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, +                tag = "Cast to other device audio only", +            )          private val TAG = "CastToOtherVM".pad()      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt index 18b0dee1c08f..b7cad625b7b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt @@ -83,6 +83,7 @@ constructor(                      )                  }              } +        val clickBehavior = OngoingActivityChipModel.ClickBehavior.None          val isShowingHeadsUpFromChipTap =              headsUpState is TopPinnedState.Pinned && @@ -91,7 +92,12 @@ constructor(          if (isShowingHeadsUpFromChipTap) {              // If the user tapped this chip to show the HUN, we want to just show the icon because              // the HUN will show the rest of the information. -            return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener) +            return OngoingActivityChipModel.Shown.IconOnly( +                icon, +                colors, +                onClickListener, +                clickBehavior, +            )          }          if (this.promotedContent.shortCriticalText != null) { @@ -100,6 +106,7 @@ constructor(                  colors,                  this.promotedContent.shortCriticalText,                  onClickListener, +                clickBehavior,              )          } @@ -111,11 +118,21 @@ constructor(              // notification will likely just be set to the current time, which would cause the chip              // to always show "now". We don't want early testers to get that experience since it's              // not what will happen at launch, so just don't show any time. -            return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener) +            return OngoingActivityChipModel.Shown.IconOnly( +                icon, +                colors, +                onClickListener, +                clickBehavior, +            )          }          if (this.promotedContent.time == null) { -            return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener) +            return OngoingActivityChipModel.Shown.IconOnly( +                icon, +                colors, +                onClickListener, +                clickBehavior, +            )          }          when (this.promotedContent.time.mode) {              PromotedNotificationContentModel.When.Mode.BasicTime -> { @@ -124,6 +141,7 @@ constructor(                      colors,                      time = this.promotedContent.time.time,                      onClickListener, +                    clickBehavior,                  )              }              PromotedNotificationContentModel.When.Mode.CountUp -> { @@ -132,6 +150,7 @@ constructor(                      colors,                      startTimeMs = this.promotedContent.time.time,                      onClickListener, +                    clickBehavior,                  )              }              PromotedNotificationContentModel.When.Mode.CountDown -> { @@ -141,6 +160,7 @@ constructor(                      colors,                      startTimeMs = this.promotedContent.time.time,                      onClickListener, +                    clickBehavior,                  )              }          } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt index 0065593c7b73..7f2327a742e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt @@ -41,6 +41,7 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel  import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel  import com.android.systemui.statusbar.chips.ui.viewmodel.ChipTransitionHelper  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel +import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener  import com.android.systemui.util.kotlin.pairwise  import com.android.systemui.util.time.SystemClock @@ -91,16 +92,24 @@ constructor(                                  ),                              colors = ColorsModel.Red,                              startTimeMs = systemClock.elapsedRealtime(), -                            createDialogLaunchOnClickListener( -                                createDelegate(state.recordedTask), -                                dialogTransitionAnimator, -                                DialogCuj( -                                    Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, -                                    tag = "Screen record", +                            onClickListenerLegacy = +                                createDialogLaunchOnClickListener( +                                    createDelegate(state.recordedTask), +                                    dialogTransitionAnimator, +                                    DIALOG_CUJ, +                                    logger, +                                    TAG, +                                ), +                            clickBehavior = +                                OngoingActivityChipModel.ClickBehavior.ExpandAction( +                                    createDialogLaunchOnClickCallback( +                                        dialogDelegate = createDelegate(state.recordedTask), +                                        dialogTransitionAnimator = dialogTransitionAnimator, +                                        DIALOG_CUJ, +                                        logger, +                                        TAG, +                                    )                                  ), -                                logger, -                                TAG, -                            ),                          )                      }                  } @@ -154,6 +163,8 @@ constructor(      companion object {          @DrawableRes val ICON = R.drawable.ic_screenrecord +        private val DIALOG_CUJ = +            DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Screen record")          private val TAG = "ScreenRecordVM".pad()      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt index 2af86a51cf70..6654d4a8f104 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt @@ -39,6 +39,7 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel  import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel  import com.android.systemui.statusbar.chips.ui.viewmodel.ChipTransitionHelper  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel +import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback  import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener  import com.android.systemui.util.time.SystemClock  import javax.inject.Inject @@ -128,13 +129,25 @@ constructor(              colors = ColorsModel.Red,              // TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.              startTimeMs = systemClock.elapsedRealtime(), -            createDialogLaunchOnClickListener( -                createShareScreenToAppDialogDelegate(state), -                dialogTransitionAnimator, -                DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Share to app"), -                logger, -                TAG, -            ), +            onClickListenerLegacy = +                createDialogLaunchOnClickListener( +                    createShareScreenToAppDialogDelegate(state), +                    dialogTransitionAnimator, +                    DIALOG_CUJ, +                    logger, +                    TAG, +                ), +            clickBehavior = +                OngoingActivityChipModel.ClickBehavior.ExpandAction( +                    onClick = +                        createDialogLaunchOnClickCallback( +                            createShareScreenToAppDialogDelegate(state), +                            dialogTransitionAnimator, +                            DIALOG_CUJ, +                            logger, +                            TAG, +                        ) +                ),          )      } @@ -150,16 +163,24 @@ constructor(                      )                  ),              colors = ColorsModel.Red, -            createDialogLaunchOnClickListener( -                createGenericShareToAppDialogDelegate(), -                dialogTransitionAnimator, -                DialogCuj( -                    Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, -                    tag = "Share to app audio only", +            onClickListenerLegacy = +                createDialogLaunchOnClickListener( +                    createGenericShareToAppDialogDelegate(), +                    dialogTransitionAnimator, +                    DIALOG_CUJ_AUDIO_ONLY, +                    logger, +                    TAG, +                ), +            clickBehavior = +                OngoingActivityChipModel.ClickBehavior.ExpandAction( +                    createDialogLaunchOnClickCallback( +                        createGenericShareToAppDialogDelegate(), +                        dialogTransitionAnimator, +                        DIALOG_CUJ_AUDIO_ONLY, +                        logger, +                        TAG, +                    )                  ), -                logger, -                TAG, -            ),          )      } @@ -180,6 +201,10 @@ constructor(      companion object {          @DrawableRes val SHARE_TO_APP_ICON = R.drawable.ic_present_to_all +        private val DIALOG_CUJ = +            DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Share to app") +        private val DIALOG_CUJ_AUDIO_ONLY = +            DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Share to app audio only")          private val TAG = "ShareToAppVM".pad()      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt index b0fa9d842480..d46638fac46c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt @@ -56,7 +56,8 @@ object OngoingActivityChipBinder {                  // Data                  setChipIcon(chipModel, chipBackgroundView, chipDefaultIconView, iconViewStore)                  setChipMainContent(chipModel, chipTextView, chipTimeView, chipShortTimeDeltaView) -                viewBinding.rootView.setOnClickListener(chipModel.onClickListener) + +                viewBinding.rootView.setOnClickListener(chipModel.onClickListenerLegacy)                  updateChipPadding(                      chipModel,                      chipBackgroundView, @@ -424,7 +425,7 @@ object OngoingActivityChipBinder {          // Clickable chips need to be a minimum size for accessibility purposes, but let          // non-clickable chips be smaller.          val minimumWidth = -            if (chipModel.onClickListener != null) { +            if (chipModel.onClickListenerLegacy != null) {                  chipBackgroundView.context.resources.getDimensionPixelSize(                      R.dimen.min_clickable_item_size                  ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt index 1be5842bceeb..6ce3228531d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt @@ -35,10 +35,13 @@ import androidx.compose.ui.Alignment  import androidx.compose.ui.Modifier  import androidx.compose.ui.draw.clip  import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape  import androidx.compose.ui.platform.LocalContext  import androidx.compose.ui.res.dimensionResource  import androidx.compose.ui.unit.dp  import androidx.compose.ui.viewinterop.AndroidView +import com.android.compose.animation.Expandable +import com.android.systemui.animation.Expandable  import com.android.systemui.common.ui.compose.Icon  import com.android.systemui.res.R  import com.android.systemui.statusbar.chips.ui.compose.modifiers.neverDecreaseWidth @@ -47,23 +50,42 @@ import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel  @Composable  fun OngoingActivityChip(model: OngoingActivityChipModel.Shown, modifier: Modifier = Modifier) { +    when (val clickBehavior = model.clickBehavior) { +        is OngoingActivityChipModel.ClickBehavior.ExpandAction -> { +            // Wrap the chip in an Expandable so we can animate the expand transition. +            ExpandableChip( +                color = { Color.Transparent }, +                shape = +                    RoundedCornerShape( +                        dimensionResource(id = R.dimen.ongoing_activity_chip_corner_radius) +                    ), +                modifier = modifier, +            ) { expandable -> +                ChipBody(model, onClick = { clickBehavior.onClick(expandable) }) +            } +        } + +        is OngoingActivityChipModel.ClickBehavior.None -> { +            ChipBody(model, modifier = modifier) +        } +    } +} + +@Composable +private fun ChipBody( +    model: OngoingActivityChipModel.Shown, +    modifier: Modifier = Modifier, +    onClick: () -> Unit = {}, +) {      val context = LocalContext.current -    val isClickable = model.onClickListener != null +    val isClickable = onClick != {}      val hasEmbeddedIcon = model.icon is OngoingActivityChipModel.ChipIcon.StatusBarView      // Use a Box with `fillMaxHeight` to create a larger click surface for the chip. The visible      // height of the chip is determined by the height of the background of the Row below.      Box(          contentAlignment = Alignment.Center, -        modifier = -            modifier -                .fillMaxHeight() -                .clickable( -                    enabled = isClickable, -                    onClick = { -                        // TODO(b/372657935): Implement click actions. -                    }, -                ), +        modifier = modifier.fillMaxHeight().clickable(enabled = isClickable, onClick = onClick),      ) {          Row(              horizontalArrangement = Arrangement.Center, @@ -206,3 +228,13 @@ private fun ChipContent(viewModel: OngoingActivityChipModel.Shown, modifier: Mod          }      }  } + +@Composable +private fun ExpandableChip( +    color: () -> Color, +    shape: Shape, +    modifier: Modifier = Modifier, +    content: @Composable (Expandable) -> Unit, +) { +    Expandable(color = color(), shape = shape, modifier = modifier.clip(shape)) { content(it) } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt index 956d99e46766..68c8f8cb4254 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt @@ -17,6 +17,7 @@  package com.android.systemui.statusbar.chips.ui.model  import android.view.View +import com.android.systemui.animation.Expandable  import com.android.systemui.common.shared.model.Icon  import com.android.systemui.statusbar.StatusBarIconView  import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips @@ -46,17 +47,20 @@ sealed class OngoingActivityChipModel {          open val colors: ColorsModel,          /**           * Listener method to invoke when this chip is clicked. If null, the chip won't be -         * clickable. +         * clickable. Will be deprecated after [StatusBarChipsModernization] is enabled.           */ -        open val onClickListener: View.OnClickListener?, +        open val onClickListenerLegacy: View.OnClickListener?, +        /** Data class that determines how clicks on the chip should be handled. */ +        open val clickBehavior: ClickBehavior,      ) : OngoingActivityChipModel() {          /** This chip shows only an icon and nothing else. */          data class IconOnly(              override val icon: ChipIcon,              override val colors: ColorsModel, -            override val onClickListener: View.OnClickListener?, -        ) : Shown(icon, colors, onClickListener) { +            override val onClickListenerLegacy: View.OnClickListener?, +            override val clickBehavior: ClickBehavior, +        ) : Shown(icon, colors, onClickListenerLegacy, clickBehavior) {              override val logName = "Shown.Icon"          } @@ -74,8 +78,9 @@ sealed class OngoingActivityChipModel {               * [android.widget.Chronometer.setBase].               */              val startTimeMs: Long, -            override val onClickListener: View.OnClickListener?, -        ) : Shown(icon, colors, onClickListener) { +            override val onClickListenerLegacy: View.OnClickListener?, +            override val clickBehavior: ClickBehavior, +        ) : Shown(icon, colors, onClickListenerLegacy, clickBehavior) {              override val logName = "Shown.Timer"          } @@ -88,8 +93,9 @@ sealed class OngoingActivityChipModel {              override val colors: ColorsModel,              /** The time of the event that this chip represents. */              val time: Long, -            override val onClickListener: View.OnClickListener?, -        ) : Shown(icon, colors, onClickListener) { +            override val onClickListenerLegacy: View.OnClickListener?, +            override val clickBehavior: ClickBehavior, +        ) : Shown(icon, colors, onClickListenerLegacy, clickBehavior) {              init {                  StatusBarNotifChips.assertInNewMode()              } @@ -105,7 +111,13 @@ sealed class OngoingActivityChipModel {              override val colors: ColorsModel,              /** The number of seconds until an event is started. */              val secondsUntilStarted: Long, -        ) : Shown(icon = null, colors, onClickListener = null) { +        ) : +            Shown( +                icon = null, +                colors, +                onClickListenerLegacy = null, +                clickBehavior = ClickBehavior.None, +            ) {              override val logName = "Shown.Countdown"          } @@ -115,8 +127,9 @@ sealed class OngoingActivityChipModel {              override val colors: ColorsModel,              // TODO(b/361346412): Enforce a max length requirement?              val text: String, -            override val onClickListener: View.OnClickListener? = null, -        ) : Shown(icon, colors, onClickListener) { +            override val onClickListenerLegacy: View.OnClickListener? = null, +            override val clickBehavior: ClickBehavior, +        ) : Shown(icon, colors, onClickListenerLegacy, clickBehavior) {              override val logName = "Shown.Text"          }      } @@ -149,4 +162,13 @@ sealed class OngoingActivityChipModel {           */          data class SingleColorIcon(val impl: Icon) : ChipIcon      } + +    /** Defines the behavior of the chip when it is clicked. */ +    sealed interface ClickBehavior { +        /** No specific click behavior. */ +        data object None : ClickBehavior + +        /** The chip expands into a dialog or activity on click. */ +        data class ExpandAction(val onClick: (Expandable) -> Unit) : ClickBehavior +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt index 2fc366b7f078..a978c04d2a2e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.chips.ui.viewmodel  import android.view.View  import com.android.systemui.animation.DialogCuj  import com.android.systemui.animation.DialogTransitionAnimator +import com.android.systemui.animation.Expandable  import com.android.systemui.log.LogBuffer  import com.android.systemui.log.core.LogLevel  import com.android.systemui.res.R @@ -26,6 +27,7 @@ import com.android.systemui.statusbar.chips.StatusBarChipsLog  import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel  import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer  import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization  import kotlinx.coroutines.flow.StateFlow  /** @@ -46,6 +48,7 @@ interface OngoingActivityChipViewModel {              tag: String,          ): View.OnClickListener {              return View.OnClickListener { view -> +                StatusBarChipsModernization.assertInLegacyMode()                  logger.log(tag, LogLevel.INFO, {}, { "Chip clicked" })                  val dialog = dialogDelegate.createDialog()                  val launchableView = @@ -55,5 +58,28 @@ interface OngoingActivityChipViewModel {                  dialogTransitionAnimator.showFromView(dialog, launchableView, cuj)              }          } + +        /** +         * Creates a chip click callback with an [Expandable] parameter that launches a dialog +         * created by [dialogDelegate]. +         */ +        fun createDialogLaunchOnClickCallback( +            dialogDelegate: SystemUIDialog.Delegate, +            dialogTransitionAnimator: DialogTransitionAnimator, +            cuj: DialogCuj, +            @StatusBarChipsLog logger: LogBuffer, +            tag: String, +        ): (Expandable) -> Unit { +            return { expandable -> +                StatusBarChipsModernization.assertInNewMode() +                logger.log(tag, LogLevel.INFO, {}, { "Chip clicked" }) +                val dialog = dialogDelegate.createDialog() + +                val controller = expandable.dialogTransitionController(cuj) +                if (controller != null) { +                    dialogTransitionAnimator.show(dialog, controller) +                } +            } +        }      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt index 2ab2b68bbb2e..9f8b45578903 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt @@ -1,18 +1,18 @@  /* -* Copyright (C) 2024 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -*      http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */  package com.android.systemui.statusbar.phone.ongoingcall  import com.android.systemui.Flags @@ -44,9 +44,16 @@ object StatusBarChipsModernization {          RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)      /** +     * Called to ensure code is only run when the flag is enabled. This will throw an exception if +     * the flag is not enabled to ensure that the refactor author catches issues in testing. +     */ +    @JvmStatic +    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME) + +    /**       * Called to ensure code is only run when the flag is disabled. This will throw an exception if       * the flag is enabled to ensure that the refactor author catches issues in testing.       */      @JvmStatic      inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME) -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java index 601b17c46c03..576e5d5d0cd2 100644 --- a/services/core/java/com/android/server/wm/AppWarnings.java +++ b/services/core/java/com/android/server/wm/AppWarnings.java @@ -51,6 +51,7 @@ import android.util.Pair;  import android.util.Slog;  import android.util.SparseArray;  import android.util.Xml; +import android.view.ContextThemeWrapper;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.util.ArrayUtils; @@ -498,10 +499,21 @@ class AppWarnings {              }          }          if (!hasPackageFlag(userId, ar.packageName, FLAG_HIDE_PAGE_SIZE_MISMATCH)) { +            Context context =  getUiContextForActivity(ar); +            // PageSizeMismatchDialog has link in message which should open in browser. +            // Starting activity from non-activity context is not allowed and flag +            // FLAG_ACTIVITY_NEW_TASK is needed to start activity. +            context =  new ContextThemeWrapper(context, context.getThemeResId()) { +                @Override +                public void startActivity(Intent intent) { +                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); +                    super.startActivity(intent); +                } +            };              pageSizeMismatchDialog =                      new PageSizeMismatchDialog(                              AppWarnings.this, -                            getUiContextForActivity(ar), +                            context,                              ar.info.applicationInfo,                              userId,                              warning); diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index 5b0cc9ab6909..fa748d3a22a5 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -28,11 +28,9 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;  import android.annotation.NonNull;  import android.content.ClipData;  import android.content.Context; -import android.hardware.display.DisplayTopology;  import android.hardware.input.InputManagerGlobal;  import android.os.Binder;  import android.os.Handler; -import android.os.HandlerExecutor;  import android.os.IBinder;  import android.os.Looper;  import android.os.Message; @@ -51,7 +49,6 @@ import android.window.IGlobalDragListener;  import android.window.IUnhandledDragCallback;  import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.hidden_from_bootclasspath.com.android.window.flags.Flags;  import com.android.server.wm.WindowManagerInternal.IDragDropCallback;  import java.util.Objects; @@ -59,7 +56,6 @@ import java.util.Random;  import java.util.concurrent.CompletableFuture;  import java.util.concurrent.TimeUnit;  import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer;  /**   * Managing drag and drop operations initiated by View#startDragAndDrop. @@ -87,8 +83,6 @@ class DragDropController {      private WindowManagerService mService;      private final Handler mHandler; -    private final Consumer<DisplayTopology> mDisplayTopologyListener = -            this::handleDisplayTopologyChange;      // The global drag listener for handling cross-window drags      private IGlobalDragListener mGlobalDragListener; @@ -114,17 +108,6 @@ class DragDropController {      DragDropController(WindowManagerService service, Looper looper) {          mService = service;          mHandler = new DragHandler(service, looper); -        if (Flags.enableConnectedDisplaysDnd()) { -            mService.mDisplayManager.registerTopologyListener( -                    new HandlerExecutor(mService.mH), mDisplayTopologyListener); -        } -    } - -    @VisibleForTesting -    void cleanupListeners() { -        if (Flags.enableConnectedDisplaysDnd()) { -            mService.mDisplayManager.unregisterTopologyListener(mDisplayTopologyListener); -        }      }      @VisibleForTesting @@ -498,18 +481,6 @@ class DragDropController {          }      } -    private void handleDisplayTopologyChange(DisplayTopology unused) { -        synchronized (mService.mGlobalLock) { -            if (mDragState == null) { -                return; -            } -            if (DEBUG_DRAG) { -                Slog.d(TAG_WM, "DisplayTopology changed, cancelling DragAndDrop"); -            } -            cancelDragAndDrop(mDragState.mToken, true /* skipAnimation */); -        } -    } -      /**       * Handles motion events.       * @param keepHandling Whether if the drag operation is continuing or this is the last motion diff --git a/services/core/java/com/android/server/wm/PageSizeMismatchDialog.java b/services/core/java/com/android/server/wm/PageSizeMismatchDialog.java index 29922f0f85c5..24235ef2d585 100644 --- a/services/core/java/com/android/server/wm/PageSizeMismatchDialog.java +++ b/services/core/java/com/android/server/wm/PageSizeMismatchDialog.java @@ -24,8 +24,10 @@ import android.content.pm.ApplicationInfo;  import android.content.pm.PackageItemInfo;  import android.content.pm.PackageManager;  import android.text.Html; +import android.text.method.LinkMovementMethod;  import android.view.Window;  import android.view.WindowManager; +import android.widget.TextView;  import com.android.internal.R; @@ -69,6 +71,14 @@ class PageSizeMismatchDialog extends AppWarnings.BaseDialog {          mDialog.create();          final Window window = mDialog.getWindow(); -        window.setType(WindowManager.LayoutParams.TYPE_PHONE); +        window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); +    } + +    @Override +    public void show() { +        super.show(); +        // Make the links in dialog clickable +        final TextView msgTxt = (TextView) mDialog.findViewById(android.R.id.message); +        msgTxt.setMovementMethod(LinkMovementMethod.getInstance());      }  } diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index 08ae6371559a..b328fc2d5868 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -101,7 +101,6 @@ android_test {          "testng",          "truth",          "wmtests-support", -        "display_flags_lib",      ],      libs: [ diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 6ced26920ff4..f509706d1692 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -32,12 +32,10 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; -import static com.android.server.display.feature.flags.Flags.FLAG_DISPLAY_TOPOLOGY;  import static com.android.server.wm.DragDropController.MSG_UNHANDLED_DROP_LISTENER_TIMEOUT;  import static org.junit.Assert.assertEquals;  import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals;  import static org.junit.Assert.assertNotNull;  import static org.junit.Assert.assertNull;  import static org.junit.Assert.assertTrue; @@ -58,7 +56,6 @@ import android.content.Intent;  import android.content.pm.ShortcutServiceInternal;  import android.graphics.PixelFormat;  import android.graphics.Rect; -import android.hardware.display.VirtualDisplay;  import android.os.Binder;  import android.os.Handler;  import android.os.IBinder; @@ -69,7 +66,6 @@ import android.os.RemoteException;  import android.os.UserHandle;  import android.platform.test.annotations.EnableFlags;  import android.platform.test.annotations.Presubmit; -import android.platform.test.annotations.RequiresFlagsEnabled;  import android.view.DragEvent;  import android.view.InputChannel;  import android.view.SurfaceControl; @@ -83,14 +79,12 @@ import androidx.test.filters.SmallTest;  import com.android.server.LocalServices;  import com.android.server.pm.UserManagerInternal; -import com.android.server.wm.utils.VirtualDisplayTestRule;  import com.android.window.flags.Flags;  import org.junit.After;  import org.junit.AfterClass;  import org.junit.Before;  import org.junit.BeforeClass; -import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.mockito.ArgumentCaptor; @@ -111,8 +105,6 @@ import java.util.function.Consumer;  @Presubmit  @RunWith(WindowTestRunner.class)  public class DragDropControllerTests extends WindowTestsBase { -    @Rule -    public VirtualDisplayTestRule mVirtualDisplayTestRule = new VirtualDisplayTestRule();      private static final int TIMEOUT_MS = 3000;      private static final int TEST_UID = 12345;      private static final int TEST_PROFILE_UID = 12345 * UserHandle.PER_USER_RANGE; @@ -228,17 +220,13 @@ public class DragDropControllerTests extends WindowTestsBase {      @After      public void tearDown() throws Exception { -        // Besides TestDragDropController, WMService also creates another DragDropController in -        // test, and since listeners are added on instantiation, it has to be cleared here as well. -        mTarget.cleanupListeners(); -        mWm.mDragDropController.cleanupListeners(); +        final CountDownLatch latch;          if (!mTarget.dragDropActiveLocked()) {              return;          }          if (mToken != null) {              mTarget.cancelDragAndDrop(mToken, false);          } -        final CountDownLatch latch;          latch = new CountDownLatch(1);          mTarget.setOnClosedCallbackLocked(latch::countDown);          if (mTarget.mIsAccessibilityDrag) { @@ -349,13 +337,12 @@ public class DragDropControllerTests extends WindowTestsBase {                      // Verify the drop event is only sent for the global intercept window                      assertTrue(nonLocalWindowDragEvents.isEmpty()); -                    assertNotEquals(ACTION_DROP, localWindowDragEvents.getLast().getAction()); -                    assertEquals(ACTION_DROP, -                            globalInterceptWindowDragEvents.getLast().getAction()); +                    assertTrue(last(localWindowDragEvents).getAction() != ACTION_DROP); +                    assertTrue(last(globalInterceptWindowDragEvents).getAction() == ACTION_DROP);                      // Verify that item extras were not sent with the drop event -                    assertNull(localWindowDragEvents.getLast().getClipData()); -                    assertFalse(globalInterceptWindowDragEvents.getLast().getClipData() +                    assertNull(last(localWindowDragEvents).getClipData()); +                    assertFalse(last(globalInterceptWindowDragEvents).getClipData()                              .willParcelWithActivityInfo());                  });      } @@ -397,7 +384,7 @@ public class DragDropControllerTests extends WindowTestsBase {      }      @Test -    public void testDragEventCoordinatesOverlappingWindows() { +    public void testDragEventCoordinates() {          int dragStartX = mWindow.getBounds().centerX();          int dragStartY = mWindow.getBounds().centerY();          int startOffsetPx = 10; @@ -442,7 +429,7 @@ public class DragDropControllerTests extends WindowTestsBase {                          // Verify only window2 received the DROP event and coords are sent as-is.                          assertEquals(1, dragEvents.size());                          assertEquals(2, dragEvents2.size()); -                        final DragEvent dropEvent = dragEvents2.getLast(); +                        final DragEvent dropEvent = last(dragEvents2);                          assertEquals(ACTION_DROP, dropEvent.getAction());                          assertEquals(dropCoordsPx, dropEvent.getX(),  0.0 /* delta */);                          assertEquals(dropCoordsPx, dropEvent.getY(),  0.0 /* delta */); @@ -450,10 +437,10 @@ public class DragDropControllerTests extends WindowTestsBase {                          mTarget.reportDropResult(iwindow2, true);                          // Verify both windows received ACTION_DRAG_ENDED event. -                        assertEquals(ACTION_DRAG_ENDED, dragEvents.getLast().getAction()); -                        assertEquals(window2.getDisplayId(), dragEvents.getLast().getDisplayId()); -                        assertEquals(ACTION_DRAG_ENDED, dragEvents2.getLast().getAction()); -                        assertEquals(window2.getDisplayId(), dragEvents2.getLast().getDisplayId()); +                        assertEquals(ACTION_DRAG_ENDED, last(dragEvents).getAction()); +                        assertEquals(window2.getDisplayId(), last(dragEvents).getDisplayId()); +                        assertEquals(ACTION_DRAG_ENDED, last(dragEvents2).getAction()); +                        assertEquals(window2.getDisplayId(), last(dragEvents2).getDisplayId());                      } finally {                          mTarget.continueDragStateClose();                      } @@ -506,7 +493,7 @@ public class DragDropControllerTests extends WindowTestsBase {                          // Verify only window2 received the DROP event and coords are sent as-is                          assertEquals(1, dragEvents.size());                          assertEquals(2, dragEvents2.size()); -                        final DragEvent dropEvent = dragEvents2.getLast(); +                        final DragEvent dropEvent = last(dragEvents2);                          assertEquals(ACTION_DROP, dropEvent.getAction());                          assertEquals(dropCoordsPx, dropEvent.getX(),  0.0 /* delta */);                          assertEquals(dropCoordsPx, dropEvent.getY(),  0.0 /* delta */); @@ -514,12 +501,10 @@ public class DragDropControllerTests extends WindowTestsBase {                          mTarget.reportDropResult(iwindow2, true);                          // Verify both windows received ACTION_DRAG_ENDED event. -                        assertEquals(ACTION_DRAG_ENDED, dragEvents.getLast().getAction()); -                        assertEquals(testDisplay.getDisplayId(), -                                dragEvents.getLast().getDisplayId()); -                        assertEquals(ACTION_DRAG_ENDED, dragEvents2.getLast().getAction()); -                        assertEquals(testDisplay.getDisplayId(), -                                dragEvents2.getLast().getDisplayId()); +                        assertEquals(ACTION_DRAG_ENDED, last(dragEvents).getAction()); +                        assertEquals(testDisplay.getDisplayId(), last(dragEvents).getDisplayId()); +                        assertEquals(ACTION_DRAG_ENDED, last(dragEvents2).getAction()); +                        assertEquals(testDisplay.getDisplayId(), last(dragEvents2).getDisplayId());                      } finally {                          mTarget.continueDragStateClose();                      } @@ -576,30 +561,8 @@ public class DragDropControllerTests extends WindowTestsBase {                  });      } -    @Test -    @RequiresFlagsEnabled(FLAG_DISPLAY_TOPOLOGY) -    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_DND) -    public void testDragCancelledOnTopologyChange() { -        VirtualDisplay virtualDisplay = createVirtualDisplay(); -        // Necessary for now since DragState.sendDragStartedLocked() will recycle drag events -        // immediately after dispatching, which is a problem when using mockito arguments captor -        // because it returns and modifies the same drag event. -        TestIWindow iwindow = (TestIWindow) mWindow.mClient; -        final ArrayList<DragEvent> dragEvents = new ArrayList<>(); -        iwindow.setDragEventJournal(dragEvents); - -        startDrag(0, 0, View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, -                ClipData.newPlainText("label", "text"), (surface) -> { -                    final CountDownLatch latch = new CountDownLatch(1); -                    mTarget.setOnClosedCallbackLocked(latch::countDown); - -                    // Release virtual display to trigger drag-and-drop cancellation. -                    virtualDisplay.release(); -                    assertTrue(awaitInWmLock(() -> latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS))); - -                    assertEquals(2, dragEvents.size()); -                    assertEquals(ACTION_DRAG_ENDED, dragEvents.getLast().getAction()); -                }); +    private DragEvent last(ArrayList<DragEvent> list) { +        return list.get(list.size() - 1);      }      @Test @@ -979,12 +942,4 @@ public class DragDropControllerTests extends WindowTestsBase {          assertNotNull(mToken);          r.run();      } - -    private VirtualDisplay createVirtualDisplay() { -        final int width = 800; -        final int height = 600; -        final String name = getClass().getSimpleName() + "_VirtualDisplay"; -        return mVirtualDisplayTestRule.createDisplayManagerAttachedVirtualDisplay(name, width, -                height); -    }  } |