1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.systemui.complication;
17 
18 import static org.junit.Assert.assertEquals;
19 import static org.mockito.ArgumentMatchers.any;
20 import static org.mockito.ArgumentMatchers.eq;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.when;
25 
26 import android.app.smartspace.SmartspaceTarget;
27 import android.testing.AndroidTestingRunner;
28 import android.view.View;
29 
30 import androidx.test.filters.SmallTest;
31 
32 import com.android.systemui.SysuiTestCase;
33 import com.android.systemui.condition.SelfExecutingMonitor;
34 import com.android.systemui.dreams.DreamOverlayStateController;
35 import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
36 import com.android.systemui.flags.FeatureFlags;
37 import com.android.systemui.flags.Flags;
38 import com.android.systemui.plugins.BcSmartspaceDataPlugin;
39 import com.android.systemui.shared.condition.Condition;
40 import com.android.systemui.shared.condition.Monitor;
41 
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.ArgumentCaptor;
46 import org.mockito.Mock;
47 import org.mockito.Mockito;
48 import org.mockito.MockitoAnnotations;
49 
50 import java.util.Collections;
51 import java.util.HashSet;
52 import java.util.Set;
53 
54 @SmallTest
55 @RunWith(AndroidTestingRunner.class)
56 public class SmartSpaceComplicationTest extends SysuiTestCase {
57 
58     @Mock
59     private DreamSmartspaceController mSmartspaceController;
60 
61     @Mock
62     private DreamOverlayStateController mDreamOverlayStateController;
63 
64     @Mock
65     private SmartSpaceComplication mComplication;
66 
67     @Mock
68     private View mBcSmartspaceView;
69 
70     @Mock
71     private FeatureFlags mFeatureFlags;
72 
73     private Monitor mMonitor;
74 
75     private final Set<Condition> mPreconditions = new HashSet<>();
76 
77     @Before
setup()78     public void setup() {
79         MockitoAnnotations.initMocks(this);
80         mMonitor = SelfExecutingMonitor.createInstance();
81 
82         when(mFeatureFlags.isEnabled(Flags.HIDE_SMARTSPACE_ON_DREAM_OVERLAY)).thenReturn(false);
83     }
84 
85     /**
86      * Ensures {@link SmartSpaceComplication} isn't registered right away on start.
87      */
88     @Test
testRegistrantStart_doesNotAddComplication()89     public void testRegistrantStart_doesNotAddComplication() {
90         final SmartSpaceComplication.Registrant registrant = getRegistrant();
91         registrant.start();
92         verify(mDreamOverlayStateController, never()).addComplication(eq(mComplication));
93     }
94 
95     @Test
testRegistrantStart_featureEnabled_addOverlayStateCallback()96     public void testRegistrantStart_featureEnabled_addOverlayStateCallback() {
97         final SmartSpaceComplication.Registrant registrant = getRegistrant();
98         registrant.start();
99 
100         verify(mDreamOverlayStateController).addCallback(any());
101     }
102 
103     @Test
testRegistrantStart_featureDisabled_doesNotAddOverlayStateCallback()104     public void testRegistrantStart_featureDisabled_doesNotAddOverlayStateCallback() {
105         when(mFeatureFlags.isEnabled(Flags.HIDE_SMARTSPACE_ON_DREAM_OVERLAY)).thenReturn(true);
106 
107         final SmartSpaceComplication.Registrant registrant = getRegistrant();
108         registrant.start();
109 
110         verify(mDreamOverlayStateController, never()).addCallback(any());
111     }
112 
113     @Test
testOverlayActive_addsTargetListener()114     public void testOverlayActive_addsTargetListener() {
115         final SmartSpaceComplication.Registrant registrant = getRegistrant();
116         registrant.start();
117 
118         final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
119                 ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
120         verify(mDreamOverlayStateController).addCallback(dreamCallbackCaptor.capture());
121 
122         when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
123         dreamCallbackCaptor.getValue().onStateChanged();
124 
125         // Test
126         final ArgumentCaptor<BcSmartspaceDataPlugin.SmartspaceTargetListener> listenerCaptor =
127                 ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
128         verify(mSmartspaceController).addListener(listenerCaptor.capture());
129     }
130 
131     @Test
testOverlayActive_targetsNonEmpty_addsComplication()132     public void testOverlayActive_targetsNonEmpty_addsComplication() {
133         final SmartSpaceComplication.Registrant registrant = getRegistrant();
134         registrant.start();
135 
136         final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
137                 ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
138         verify(mDreamOverlayStateController).addCallback(dreamCallbackCaptor.capture());
139 
140         when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
141         dreamCallbackCaptor.getValue().onStateChanged();
142 
143         final ArgumentCaptor<BcSmartspaceDataPlugin.SmartspaceTargetListener> listenerCaptor =
144                 ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
145         verify(mSmartspaceController).addListener(listenerCaptor.capture());
146 
147         // Test
148         final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class);
149         listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.singletonList(target));
150         verify(mDreamOverlayStateController).addComplication(eq(mComplication));
151     }
152 
153     @Test
testOverlayActive_targetsEmpty_addsComplication()154     public void testOverlayActive_targetsEmpty_addsComplication() {
155         final SmartSpaceComplication.Registrant registrant = getRegistrant();
156         registrant.start();
157 
158         final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
159                 ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
160         verify(mDreamOverlayStateController).addCallback(dreamCallbackCaptor.capture());
161 
162         when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
163         dreamCallbackCaptor.getValue().onStateChanged();
164 
165         final ArgumentCaptor<BcSmartspaceDataPlugin.SmartspaceTargetListener> listenerCaptor =
166                 ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
167         verify(mSmartspaceController).addListener(listenerCaptor.capture());
168 
169         // Test
170         listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.emptyList());
171         verify(mDreamOverlayStateController).addComplication(eq(mComplication));
172     }
173 
174     @Test
testOverlayInActive_removesTargetListener_removesComplication()175     public void testOverlayInActive_removesTargetListener_removesComplication() {
176         final SmartSpaceComplication.Registrant registrant = getRegistrant();
177         registrant.start();
178 
179         final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
180                 ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
181         verify(mDreamOverlayStateController).addCallback(dreamCallbackCaptor.capture());
182 
183         when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
184         dreamCallbackCaptor.getValue().onStateChanged();
185 
186         final ArgumentCaptor<BcSmartspaceDataPlugin.SmartspaceTargetListener> listenerCaptor =
187                 ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
188         verify(mSmartspaceController).addListener(listenerCaptor.capture());
189 
190         listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.emptyList());
191         verify(mDreamOverlayStateController).addComplication(eq(mComplication));
192 
193         // Test
194         when(mDreamOverlayStateController.isOverlayActive()).thenReturn(false);
195         dreamCallbackCaptor.getValue().onStateChanged();
196         verify(mSmartspaceController).removeListener(listenerCaptor.getValue());
197         verify(mDreamOverlayStateController).removeComplication(eq(mComplication));
198     }
199 
200     @Test
testGetView_reusesSameView()201     public void testGetView_reusesSameView() {
202         final Complication.ViewHolder viewHolder =
203                 new SmartSpaceComplication.SmartSpaceComplicationViewHolder(getContext(),
204                         mSmartspaceController, mock(ComplicationLayoutParams.class));
205         when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mBcSmartspaceView);
206         assertEquals(viewHolder.getView(), viewHolder.getView());
207     }
208 
getRegistrant()209     private SmartSpaceComplication.Registrant getRegistrant() {
210         return new SmartSpaceComplication.Registrant(
211                 mDreamOverlayStateController,
212                 mComplication,
213                 mSmartspaceController,
214                 mMonitor,
215                 mFeatureFlags);
216     }
217 }
218