diff options
| author | 2022-08-31 16:53:24 +0000 | |
|---|---|---|
| committer | 2022-08-31 16:53:24 +0000 | |
| commit | bd264a9f3265c0a56d28e6d220ba5e3409c730b3 (patch) | |
| tree | c5581a9af4da22a9d34304145e5da7d818b6fb8f | |
| parent | 4a3d0cb401bb11786d50ef70a7a498a5d51bc65c (diff) | |
| parent | 6e4eaa487fc8fa07bf5c614434d005ccdff4ee8d (diff) | |
Merge "Add media entry Dream complication." into tm-qpr-dev am: 6e4eaa487f
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19732912
Change-Id: Ibd3ecec76a3bd036e027afcd59c169f79dd1213f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
10 files changed, 378 insertions, 13 deletions
diff --git a/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml b/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml new file mode 100644 index 000000000000..50f3ffcaf968 --- /dev/null +++ b/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. +--> +<ImageView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/media_entry_chip" + android:layout_height="@dimen/keyguard_affordance_fixed_height" + android:layout_width="@dimen/keyguard_affordance_fixed_width" + android:layout_gravity="bottom|start" + android:scaleType="center" + android:tint="?android:attr/textColorPrimary" + android:src="@drawable/ic_music_note" + android:background="@drawable/keyguard_bottom_affordance_bg" + android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset" + android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset" + android:contentDescription="@string/controls_media_title" /> diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java index d5db63dc9093..75a97de10e7e 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java @@ -35,7 +35,7 @@ import java.util.Set; public class ComplicationUtils { /** * Converts a {@link com.android.settingslib.dream.DreamBackend.ComplicationType} to - * {@link ComplicationType}. + * {@link Complication.ComplicationType}. */ @Complication.ComplicationType public static int convertComplicationType(@DreamBackend.ComplicationType int type) { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java index 1c72e49eb06a..2503d3c3edad 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java @@ -151,8 +151,8 @@ public class DreamHomeControlsComplication implements Complication { * Controls behavior of the dream complication. */ static class DreamHomeControlsChipViewController extends ViewController<ImageView> { - private static final boolean DEBUG = false; private static final String TAG = "DreamHomeControlsCtrl"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final ActivityStarter mActivityStarter; private final Context mContext; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java new file mode 100644 index 000000000000..21a51d1096d5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2022 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.dreams.complication; + +import static com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent.DreamMediaEntryModule.DREAM_MEDIA_ENTRY_VIEW; +import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_ENTRY_LAYOUT_PARAMS; + +import android.util.Log; +import android.view.View; + +import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent; +import com.android.systemui.media.dream.MediaDreamComplication; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * A dream complication that shows a media entry chip to launch media control view. + */ +public class DreamMediaEntryComplication implements Complication { + private final DreamMediaEntryComplicationComponent.Factory mComponentFactory; + + @Inject + public DreamMediaEntryComplication( + DreamMediaEntryComplicationComponent.Factory componentFactory) { + mComponentFactory = componentFactory; + } + + @Override + public ViewHolder createView(ComplicationViewModel model) { + return mComponentFactory.create().getViewHolder(); + } + + /** + * Contains values/logic associated with the dream complication view. + */ + public static class DreamMediaEntryViewHolder implements ViewHolder { + private final View mView; + private final ComplicationLayoutParams mLayoutParams; + private final DreamMediaEntryViewController mViewController; + + @Inject + DreamMediaEntryViewHolder( + DreamMediaEntryViewController dreamMediaEntryViewController, + @Named(DREAM_MEDIA_ENTRY_VIEW) View view, + @Named(DREAM_MEDIA_ENTRY_LAYOUT_PARAMS) ComplicationLayoutParams layoutParams + ) { + mView = view; + mLayoutParams = layoutParams; + mViewController = dreamMediaEntryViewController; + mViewController.init(); + } + + @Override + public View getView() { + return mView; + } + + @Override + public ComplicationLayoutParams getLayoutParams() { + return mLayoutParams; + } + } + + /** + * Controls behavior of the dream complication. + */ + static class DreamMediaEntryViewController extends ViewController<View> { + private static final String TAG = "DreamMediaEntryVwCtrl"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final DreamOverlayStateController mDreamOverlayStateController; + private final MediaDreamComplication mMediaComplication; + + private boolean mMediaComplicationAdded; + + @Inject + DreamMediaEntryViewController( + @Named(DREAM_MEDIA_ENTRY_VIEW) View view, + DreamOverlayStateController dreamOverlayStateController, + MediaDreamComplication mediaComplication) { + super(view); + mDreamOverlayStateController = dreamOverlayStateController; + mMediaComplication = mediaComplication; + mView.setOnClickListener(this::onClickMediaEntry); + } + + @Override + protected void onViewAttached() { + } + + @Override + protected void onViewDetached() { + removeMediaComplication(); + } + + private void onClickMediaEntry(View v) { + if (DEBUG) Log.d(TAG, "media entry complication tapped"); + + if (!mMediaComplicationAdded) { + addMediaComplication(); + } else { + removeMediaComplication(); + } + } + + private void addMediaComplication() { + mView.setSelected(true); + mDreamOverlayStateController.addComplication(mMediaComplication); + mMediaComplicationAdded = true; + } + + private void removeMediaComplication() { + mView.setSelected(false); + mDreamOverlayStateController.removeComplication(mMediaComplication); + mMediaComplicationAdded = false; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamMediaEntryComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamMediaEntryComplicationComponent.java new file mode 100644 index 000000000000..ed05daf35ed9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamMediaEntryComplicationComponent.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2022 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.dreams.complication.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import android.view.LayoutInflater; +import android.view.View; + +import com.android.systemui.R; +import com.android.systemui.dreams.complication.DreamMediaEntryComplication; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Named; +import javax.inject.Scope; + +import dagger.Module; +import dagger.Provides; +import dagger.Subcomponent; + +/** + * Responsible for generating dependencies for the {@link DreamMediaEntryComplication}. + */ +@Subcomponent(modules = DreamMediaEntryComplicationComponent.DreamMediaEntryModule.class) +@DreamMediaEntryComplicationComponent.DreamMediaEntryComplicationScope +public interface DreamMediaEntryComplicationComponent { + /** + * Creates a view holder for the media entry complication. + */ + DreamMediaEntryComplication.DreamMediaEntryViewHolder getViewHolder(); + + /** + * Scope of the media entry complication. + */ + @Documented + @Retention(RUNTIME) + @Scope + @interface DreamMediaEntryComplicationScope {} + + /** + * Factory that generates a {@link DreamMediaEntryComplicationComponent}. + */ + @Subcomponent.Factory + interface Factory { + DreamMediaEntryComplicationComponent create(); + } + + /** + * Scoped injected values for the {@link DreamMediaEntryComplicationComponent}. + */ + @Module + interface DreamMediaEntryModule { + String DREAM_MEDIA_ENTRY_VIEW = "dream_media_entry_view"; + + /** + * Provides the dream media entry view. + */ + @Provides + @DreamMediaEntryComplicationScope + @Named(DREAM_MEDIA_ENTRY_VIEW) + static View provideMediaEntryView(LayoutInflater layoutInflater) { + return (View) layoutInflater.inflate(R.layout.dream_overlay_media_entry_chip, null); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java index eb07238ce752..759d6ec3bf21 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java @@ -38,15 +38,19 @@ import dagger.Provides; }, subcomponents = { DreamHomeControlsComplicationComponent.class, + DreamMediaEntryComplicationComponent.class }) public interface RegisteredComplicationsModule { String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS = "time_complication_layout_params"; String DREAM_SMARTSPACE_LAYOUT_PARAMS = "smartspace_layout_params"; String DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS = "home_controls_chip_layout_params"; + String DREAM_MEDIA_ENTRY_LAYOUT_PARAMS = "media_entry_layout_params"; int DREAM_CLOCK_TIME_COMPLICATION_WEIGHT = 1; int DREAM_SMARTSPACE_COMPLICATION_WEIGHT = 0; + int DREAM_MEDIA_COMPLICATION_WEIGHT = -1; int DREAM_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT = 1; + int DREAM_MEDIA_ENTRY_COMPLICATION_WEIGHT = 0; /** * Provides layout parameters for the clock time complication. @@ -78,6 +82,21 @@ public interface RegisteredComplicationsModule { } /** + * Provides layout parameters for the media entry complication. + */ + @Provides + @Named(DREAM_MEDIA_ENTRY_LAYOUT_PARAMS) + static ComplicationLayoutParams provideMediaEntryLayoutParams(@Main Resources res) { + return new ComplicationLayoutParams( + res.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width), + res.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height), + ComplicationLayoutParams.POSITION_BOTTOM + | ComplicationLayoutParams.POSITION_START, + ComplicationLayoutParams.DIRECTION_END, + DREAM_MEDIA_ENTRY_COMPLICATION_WEIGHT); + } + + /** * Provides layout parameters for the smartspace complication. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java index c5448713970c..acd04f216a98 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java +++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java @@ -25,6 +25,7 @@ import androidx.annotation.Nullable; import com.android.systemui.CoreStartable; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.dreams.complication.DreamMediaEntryComplication; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.MediaData; import com.android.systemui.media.MediaDataManager; @@ -54,7 +55,7 @@ public class MediaDreamSentinel extends CoreStartable { } mAdded = false; - mDreamOverlayStateController.removeComplication(mComplication); + mDreamOverlayStateController.removeComplication(mMediaEntryComplication); } @Override @@ -79,24 +80,24 @@ public class MediaDreamSentinel extends CoreStartable { } mAdded = true; - mDreamOverlayStateController.addComplication(mComplication); + mDreamOverlayStateController.addComplication(mMediaEntryComplication); } }; private final MediaDataManager mMediaDataManager; private final DreamOverlayStateController mDreamOverlayStateController; - private final MediaDreamComplication mComplication; + private final DreamMediaEntryComplication mMediaEntryComplication; private final FeatureFlags mFeatureFlags; @Inject public MediaDreamSentinel(Context context, MediaDataManager mediaDataManager, DreamOverlayStateController dreamOverlayStateController, - MediaDreamComplication complication, + DreamMediaEntryComplication mediaEntryComplication, FeatureFlags featureFlags) { super(context); mMediaDataManager = mediaDataManager; mDreamOverlayStateController = dreamOverlayStateController; - mComplication = complication; + mMediaEntryComplication = mediaEntryComplication; mFeatureFlags = featureFlags; } diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java index 3408d97dd33f..052608f17e0e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java +++ b/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java @@ -16,6 +16,8 @@ package com.android.systemui.media.dream.dagger; +import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_COMPLICATION_WEIGHT; + import static java.lang.annotation.RetentionPolicy.RUNTIME; import android.content.Context; @@ -93,7 +95,7 @@ public interface MediaComplicationComponent { ComplicationLayoutParams.POSITION_TOP | ComplicationLayoutParams.POSITION_START, ComplicationLayoutParams.DIRECTION_DOWN, - 0, + DREAM_MEDIA_COMPLICATION_WEIGHT, true); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java new file mode 100644 index 000000000000..bc944404efe6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 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.dreams.complication; + +import static org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.media.dream.MediaDreamComplication; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DreamMediaEntryComplicationTest extends SysuiTestCase { + @Mock + private View mView; + + @Mock + private DreamOverlayStateController mDreamOverlayStateController; + + @Mock + private MediaDreamComplication mMediaComplication; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + } + + /** + * Ensures clicking media entry chip adds/removes media complication. + */ + @Test + public void testClick() { + final DreamMediaEntryComplication.DreamMediaEntryViewController viewController = + new DreamMediaEntryComplication.DreamMediaEntryViewController( + mView, + mDreamOverlayStateController, + mMediaComplication); + + final ArgumentCaptor<View.OnClickListener> clickListenerCaptor = + ArgumentCaptor.forClass(View.OnClickListener.class); + verify(mView).setOnClickListener(clickListenerCaptor.capture()); + + clickListenerCaptor.getValue().onClick(mView); + verify(mView).setSelected(true); + verify(mDreamOverlayStateController).addComplication(mMediaComplication); + clickListenerCaptor.getValue().onClick(mView); + verify(mView).setSelected(false); + verify(mDreamOverlayStateController).removeComplication(mMediaComplication); + } + + /** + * Ensures media complication is removed when the view is detached. + */ + @Test + public void testOnViewDetached() { + final DreamMediaEntryComplication.DreamMediaEntryViewController viewController = + new DreamMediaEntryComplication.DreamMediaEntryViewController( + mView, + mDreamOverlayStateController, + mMediaComplication); + + viewController.onViewDetached(); + verify(mView).setSelected(false); + verify(mDreamOverlayStateController).removeComplication(mMediaComplication); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java index c101b9ffd495..2e864dc2cda8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java @@ -18,6 +18,7 @@ package com.android.systemui.media.dream; import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION; +import static org.mockito.AdditionalMatchers.not; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; @@ -30,6 +31,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.dreams.complication.DreamMediaEntryComplication; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.MediaData; import com.android.systemui.media.MediaDataManager; @@ -51,7 +53,7 @@ public class MediaDreamSentinelTest extends SysuiTestCase { DreamOverlayStateController mDreamOverlayStateController; @Mock - MediaDreamComplication mComplication; + DreamMediaEntryComplication mMediaEntryComplication; @Mock FeatureFlags mFeatureFlags; @@ -72,7 +74,7 @@ public class MediaDreamSentinelTest extends SysuiTestCase { @Test public void testComplicationAddition() { final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager, - mDreamOverlayStateController, mComplication, mFeatureFlags); + mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags); sentinel.start(); @@ -85,14 +87,16 @@ public class MediaDreamSentinelTest extends SysuiTestCase { when(mMediaDataManager.hasActiveMedia()).thenReturn(true); listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true, /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false); - verify(mDreamOverlayStateController).addComplication(eq(mComplication)); + verify(mDreamOverlayStateController).addComplication(eq(mMediaEntryComplication)); + verify(mDreamOverlayStateController, never()).addComplication( + not(eq(mMediaEntryComplication))); listener.onMediaDataRemoved(mKey); verify(mDreamOverlayStateController, never()).removeComplication(any()); when(mMediaDataManager.hasActiveMedia()).thenReturn(false); listener.onMediaDataRemoved(mKey); - verify(mDreamOverlayStateController).removeComplication(eq(mComplication)); + verify(mDreamOverlayStateController).removeComplication(eq(mMediaEntryComplication)); } @Test @@ -100,7 +104,7 @@ public class MediaDreamSentinelTest extends SysuiTestCase { when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(false); final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager, - mDreamOverlayStateController, mComplication, mFeatureFlags); + mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags); sentinel.start(); |