SmartSpace Complication Introduction.

This changelist introduces the SmartSpace Complication, which provides the same at a glance view found on the lockscreen.

Bug: 213907299
Test: atest SmartSpaceComplicationTest
Change-Id: Id235112bd76f313e8678520035d90dc8672fd967
diff --git a/packages/SystemUI/res/layout/dream_overlay_complications_layer.xml b/packages/SystemUI/res/layout/dream_overlay_complications_layer.xml
index aaff3f9..2d565a1 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complications_layer.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complications_layer.xml
@@ -20,6 +20,34 @@
     android:id="@+id/dream_overlay_complications_layer"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
+    <TextClock
+        android:id="@+id/time_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:fontFamily="sans-serif-thin"
+        android:format12Hour="h:mm"
+        android:format24Hour="kk:mm"
+        android:shadowColor="#B2000000"
+        android:shadowRadius="2.0"
+        android:singleLine="true"
+        android:textSize="72sp"
+        android:textColor="@android:color/white"
+        app:layout_constraintBottom_toTopOf="@+id/date_view"
+        app:layout_constraintStart_toStartOf="parent" />
+    <TextClock
+        android:id="@+id/date_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:shadowColor="#B2000000"
+        android:shadowRadius="2.0"
+        android:format12Hour="EEE, MMM d"
+        android:format24Hour="EEE, MMM d"
+        android:singleLine="true"
+        android:textSize="18sp"
+        android:textColor="@android:color/white"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="@+id/time_view"
+        app:layout_constraintStart_toStartOf="@+id/time_view" />
     <androidx.constraintlayout.widget.Guideline
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -44,30 +72,4 @@
         android:id="@+id/complication_start_guide"
         app:layout_constraintGuide_percent="@dimen/dream_overlay_complication_guide_start_percent"
         android:orientation="vertical"/>
-    <TextClock
-        android:id="@+id/time_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:fontFamily="sans-serif-thin"
-        android:format12Hour="h:mm"
-        android:format24Hour="kk:mm"
-        android:shadowColor="#B2000000"
-        android:shadowRadius="2.0"
-        android:singleLine="true"
-        android:textSize="72sp"
-        app:layout_constraintBottom_toTopOf="@+id/date_view"
-        app:layout_constraintStart_toStartOf="parent" />
-    <TextClock
-        android:id="@+id/date_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:shadowColor="#B2000000"
-        android:shadowRadius="2.0"
-        android:format12Hour="EEE, MMM d"
-        android:format24Hour="EEE, MMM d"
-        android:singleLine="true"
-        android:textSize="18sp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="@+id/time_view"
-        app:layout_constraintStart_toStartOf="@+id/time_view" />
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 96e2302..0311740 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -26,6 +26,7 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.clipboardoverlay.ClipboardListener;
 import com.android.systemui.dreams.DreamOverlayRegistrant;
+import com.android.systemui.dreams.SmartSpaceComplication;
 import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
@@ -218,4 +219,11 @@
     @ClassKey(DreamOverlayRegistrant.class)
     public abstract CoreStartable bindDreamOverlayRegistrant(
             DreamOverlayRegistrant dreamOverlayRegistrant);
+
+    /** Inject into SmartSpaceComplication.Registrant */
+    @Binds
+    @IntoMap
+    @ClassKey(SmartSpaceComplication.Registrant.class)
+    public abstract CoreStartable bindSmartSpaceComplicationRegistrant(
+            SmartSpaceComplication.Registrant registrant);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
new file mode 100644
index 0000000..09221b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
@@ -0,0 +1,113 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.ComplicationViewModel;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
+
+import javax.inject.Inject;
+
+/**
+ * {@link SmartSpaceComplication} embodies the SmartSpace view found on the lockscreen as a
+ * {@link Complication}
+ */
+public class SmartSpaceComplication implements Complication {
+    /**
+     * {@link CoreStartable} responsbile for registering {@link SmartSpaceComplication} with
+     * SystemUI.
+     */
+    public static class Registrant extends CoreStartable {
+        private final LockscreenSmartspaceController mSmartSpaceController;
+        private final DreamOverlayStateController mDreamOverlayStateController;
+        private final SmartSpaceComplication mComplication;
+
+        /**
+         * Default constructor for {@link SmartSpaceComplication}.
+         */
+        @Inject
+        public Registrant(Context context,
+                DreamOverlayStateController dreamOverlayStateController,
+                SmartSpaceComplication smartSpaceComplication,
+                LockscreenSmartspaceController smartSpaceController) {
+            super(context);
+            mDreamOverlayStateController = dreamOverlayStateController;
+            mComplication = smartSpaceComplication;
+            mSmartSpaceController = smartSpaceController;
+        }
+
+        @Override
+        public void start() {
+            if (mSmartSpaceController.isEnabled()) {
+                mDreamOverlayStateController.addComplication(mComplication);
+            }
+        }
+    }
+
+    private static class SmartSpaceComplicationViewHolder implements ViewHolder {
+        private final LockscreenSmartspaceController mSmartSpaceController;
+        private final Context mContext;
+
+        protected SmartSpaceComplicationViewHolder(
+                Context context,
+                LockscreenSmartspaceController smartSpaceController) {
+            mSmartSpaceController = smartSpaceController;
+            mContext = context;
+        }
+
+        @Override
+        public View getView() {
+            final FrameLayout smartSpaceContainer = new FrameLayout(mContext);
+            smartSpaceContainer.addView(
+                    mSmartSpaceController.buildAndConnectView(smartSpaceContainer),
+                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.WRAP_CONTENT));
+
+            return smartSpaceContainer;
+        }
+
+        @Override
+        public ComplicationLayoutParams getLayoutParams() {
+            return new ComplicationLayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ComplicationLayoutParams.POSITION_TOP | ComplicationLayoutParams.POSITION_START,
+                    ComplicationLayoutParams.DIRECTION_DOWN,
+                    0, true);
+        }
+    }
+
+    private final LockscreenSmartspaceController mSmartSpaceController;
+    private final Context mContext;
+
+    @Inject
+    public SmartSpaceComplication(Context context,
+            LockscreenSmartspaceController smartSpaceController) {
+        mContext = context;
+        mSmartSpaceController = smartSpaceController;
+    }
+
+    @Override
+    public ViewHolder createView(ComplicationViewModel model) {
+        return new SmartSpaceComplicationViewHolder(mContext, mSmartSpaceController);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java
new file mode 100644
index 0000000..3b17a80
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class SmartSpaceComplicationTest extends SysuiTestCase {
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private LockscreenSmartspaceController mSmartspaceController;
+
+    @Mock
+    private DreamOverlayStateController mDreamOverlayStateController;
+
+    @Mock
+    private SmartSpaceComplication mComplication;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * Ensures {@link SmartSpaceComplication} is only registered when it is available.
+     */
+    @Test
+    public void testAvailability() {
+        when(mSmartspaceController.isEnabled()).thenReturn(false);
+
+        final SmartSpaceComplication.Registrant registrant = new SmartSpaceComplication.Registrant(
+                mContext,
+                mDreamOverlayStateController,
+                mComplication,
+                mSmartspaceController);
+        registrant.start();
+        verify(mDreamOverlayStateController, never()).addComplication(any());
+
+        when(mSmartspaceController.isEnabled()).thenReturn(true);
+        registrant.start();
+        verify(mDreamOverlayStateController).addComplication(eq(mComplication));
+    }
+}