Remove SmartSpaceComplication when the SmartspaceTargetListener is removed.
The listener removes the SmartSpaceComplication when the targets becomes empty. If the listener isn't connected, we don't know whether/when the targets becomes empty. Therefore we should just remove the complication when the listener is removed. This fixes the extra DATE card impression on the Dream surface. The CardPagerAdapter adds a default DATE card when its setTargets method is called with an empty list. This CL ensures that for Dream Smartspace, the setTargets method is never called with an empty list. Reorganized the existing testAvailability() test into multiple tests. The new logic is tested in testOverlayInActive_removesTargetListener_removesComplication(). Bug: 231251252 Test: on device via `adb logcat ...` Test: atest SmartSpaceComplicationTest Change-Id: Iac0d8a9697f42e2c70c83c5da050f17190fcc3c1
This commit is contained in:
@@ -101,6 +101,9 @@ public class DreamOverlayStateController implements
|
||||
public void addComplication(Complication complication) {
|
||||
mExecutor.execute(() -> {
|
||||
if (mComplications.add(complication)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "addComplication: added " + complication);
|
||||
}
|
||||
mCallbacks.stream().forEach(callback -> callback.onComplicationsChanged());
|
||||
}
|
||||
});
|
||||
@@ -112,6 +115,9 @@ public class DreamOverlayStateController implements
|
||||
public void removeComplication(Complication complication) {
|
||||
mExecutor.execute(() -> {
|
||||
if (mComplications.remove(complication)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "removeComplication: removed " + complication);
|
||||
}
|
||||
mCallbacks.stream().forEach(callback -> callback.onComplicationsChanged());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -82,6 +82,7 @@ public class SmartSpaceComplication implements Complication {
|
||||
mSmartSpaceController.addListener(mSmartspaceListener);
|
||||
} else {
|
||||
mSmartSpaceController.removeListener(mSmartspaceListener);
|
||||
mDreamOverlayStateController.removeComplication(mComplication);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.systemui.dreams.complication.dagger.ComplicationModule
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.os.Debug;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
@@ -44,7 +45,8 @@ import javax.inject.Named;
|
||||
* a {@link ComplicationLayoutEngine}.
|
||||
*/
|
||||
public class ComplicationHostViewController extends ViewController<ConstraintLayout> {
|
||||
public static final String TAG = "ComplicationHostVwCtrl";
|
||||
private static final String TAG = "ComplicationHostVwCtrl";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private final ComplicationLayoutEngine mLayoutEngine;
|
||||
private final LifecycleOwner mLifecycleOwner;
|
||||
@@ -90,6 +92,11 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
|
||||
}
|
||||
|
||||
private void updateComplications(Collection<ComplicationViewModel> complications) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "updateComplications called. Callers = " + Debug.getCallers(25));
|
||||
Log.d(TAG, " mComplications = " + mComplications.toString());
|
||||
Log.d(TAG, " complications = " + complications.toString());
|
||||
}
|
||||
final Collection<ComplicationId> ids = complications.stream()
|
||||
.map(complicationViewModel -> complicationViewModel.getId())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
@@ -54,7 +54,7 @@ import javax.inject.Named;
|
||||
*/
|
||||
@DreamOverlayComponent.DreamOverlayScope
|
||||
public class ComplicationLayoutEngine implements Complication.VisibilityController {
|
||||
public static final String TAG = "ComplicationLayoutEngine";
|
||||
public static final String TAG = "ComplicationLayoutEng";
|
||||
|
||||
/**
|
||||
* {@link ViewEntry} is an internal container, capturing information necessary for working with
|
||||
@@ -529,7 +529,7 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll
|
||||
*/
|
||||
public void addComplication(ComplicationId id, View view,
|
||||
ComplicationLayoutParams lp, @Complication.Category int category) {
|
||||
Log.d(TAG, "engine: " + this + " addComplication");
|
||||
Log.d(TAG, "@" + Integer.toHexString(this.hashCode()) + " addComplication: " + id);
|
||||
|
||||
// If the complication is present, remove.
|
||||
if (mEntries.containsKey(id)) {
|
||||
|
||||
@@ -64,4 +64,9 @@ public class ComplicationViewModel extends ViewModel {
|
||||
public void exitDream() {
|
||||
mHost.requestExitDream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mId + "=" + mComplication.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,19 +72,67 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures {@link SmartSpaceComplication} is only registered when it is available.
|
||||
* Ensures {@link SmartSpaceComplication} isn't registered right away on start.
|
||||
*/
|
||||
@Test
|
||||
public void testAvailability() {
|
||||
public void testRegistrantStart_doesNotAddComplication() {
|
||||
final SmartSpaceComplication.Registrant registrant = getRegistrant();
|
||||
registrant.start();
|
||||
verify(mDreamOverlayStateController, never()).addComplication(eq(mComplication));
|
||||
}
|
||||
|
||||
final SmartSpaceComplication.Registrant registrant = new SmartSpaceComplication.Registrant(
|
||||
private SmartSpaceComplication.Registrant getRegistrant() {
|
||||
return new SmartSpaceComplication.Registrant(
|
||||
mContext,
|
||||
mDreamOverlayStateController,
|
||||
mComplication,
|
||||
mSmartspaceController);
|
||||
registrant.start();
|
||||
verify(mDreamOverlayStateController, never()).addComplication(eq(mComplication));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlayActive_addsTargetListener() {
|
||||
final SmartSpaceComplication.Registrant registrant = getRegistrant();
|
||||
registrant.start();
|
||||
|
||||
final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
|
||||
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
|
||||
verify(mDreamOverlayStateController).addCallback(dreamCallbackCaptor.capture());
|
||||
|
||||
when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
|
||||
dreamCallbackCaptor.getValue().onStateChanged();
|
||||
|
||||
// Test
|
||||
final ArgumentCaptor<BcSmartspaceDataPlugin.SmartspaceTargetListener> listenerCaptor =
|
||||
ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
|
||||
verify(mSmartspaceController).addListener(listenerCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlayActive_targetsNonEmpty_addsComplication() {
|
||||
final SmartSpaceComplication.Registrant registrant = getRegistrant();
|
||||
registrant.start();
|
||||
|
||||
final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
|
||||
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
|
||||
verify(mDreamOverlayStateController).addCallback(dreamCallbackCaptor.capture());
|
||||
|
||||
when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
|
||||
dreamCallbackCaptor.getValue().onStateChanged();
|
||||
|
||||
final ArgumentCaptor<BcSmartspaceDataPlugin.SmartspaceTargetListener> listenerCaptor =
|
||||
ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
|
||||
verify(mSmartspaceController).addListener(listenerCaptor.capture());
|
||||
|
||||
// Test
|
||||
final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class);
|
||||
listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target));
|
||||
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlayActive_targetsEmpty_removesComplication() {
|
||||
final SmartSpaceComplication.Registrant registrant = getRegistrant();
|
||||
registrant.start();
|
||||
|
||||
final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
|
||||
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
|
||||
@@ -100,10 +148,41 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
|
||||
final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class);
|
||||
listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target));
|
||||
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
|
||||
|
||||
// Test
|
||||
listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList());
|
||||
verify(mDreamOverlayStateController).removeComplication(eq(mComplication));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetViewReusesSameView() {
|
||||
public void testOverlayInActive_removesTargetListener_removesComplication() {
|
||||
final SmartSpaceComplication.Registrant registrant = getRegistrant();
|
||||
registrant.start();
|
||||
|
||||
final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
|
||||
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
|
||||
verify(mDreamOverlayStateController).addCallback(dreamCallbackCaptor.capture());
|
||||
|
||||
when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
|
||||
dreamCallbackCaptor.getValue().onStateChanged();
|
||||
|
||||
final ArgumentCaptor<BcSmartspaceDataPlugin.SmartspaceTargetListener> listenerCaptor =
|
||||
ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
|
||||
verify(mSmartspaceController).addListener(listenerCaptor.capture());
|
||||
|
||||
final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class);
|
||||
listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target));
|
||||
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
|
||||
|
||||
// Test
|
||||
when(mDreamOverlayStateController.isOverlayActive()).thenReturn(false);
|
||||
dreamCallbackCaptor.getValue().onStateChanged();
|
||||
verify(mSmartspaceController).removeListener(listenerCaptor.getValue());
|
||||
verify(mDreamOverlayStateController).removeComplication(eq(mComplication));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetView_reusesSameView() {
|
||||
final SmartSpaceComplication complication = new SmartSpaceComplication(getContext(),
|
||||
mSmartspaceController);
|
||||
final Complication.ViewHolder viewHolder = complication.createView(mComplicationViewModel);
|
||||
|
||||
Reference in New Issue
Block a user