Add unfiltered access to the dream smartspace targets, in order to

extract weather data.

Weather data is filtered from showing in the dream smartspace view.
However, we need to extract the weather card for the weather
complication. Therefore we need unfiltered access to the weather data,
which this change adds.

Bug: 231973747
Test: locally on device
Test: atest DreamWeatherComplicationTest
Change-Id: Ic2f815720ad554091f7ca068845e421f0e0baf23
This commit is contained in:
Lucas Silva
2022-06-06 15:14:02 -04:00
parent 9e11648fb5
commit ae623e1426
3 changed files with 59 additions and 28 deletions

View File

@@ -33,9 +33,9 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.R;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent;
import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
@@ -73,7 +73,6 @@ public class DreamWeatherComplication implements Complication {
* {@link CoreStartable} for registering {@link DreamWeatherComplication} with SystemUI.
*/
public static class Registrant extends CoreStartable {
private final LockscreenSmartspaceController mSmartSpaceController;
private final DreamOverlayStateController mDreamOverlayStateController;
private final DreamWeatherComplication mComplication;
@@ -82,20 +81,16 @@ public class DreamWeatherComplication implements Complication {
*/
@Inject
public Registrant(Context context,
LockscreenSmartspaceController smartspaceController,
DreamOverlayStateController dreamOverlayStateController,
DreamWeatherComplication dreamWeatherComplication) {
super(context);
mSmartSpaceController = smartspaceController;
mDreamOverlayStateController = dreamOverlayStateController;
mComplication = dreamWeatherComplication;
}
@Override
public void start() {
if (mSmartSpaceController.isEnabled()) {
mDreamOverlayStateController.addComplication(mComplication);
}
mDreamOverlayStateController.addComplication(mComplication);
}
}
@@ -134,7 +129,7 @@ public class DreamWeatherComplication implements Complication {
* ViewController to contain value/logic associated with a Weather Complication View.
*/
static class DreamWeatherViewController extends ViewController<TextView> {
private final LockscreenSmartspaceController mSmartSpaceController;
private final DreamSmartspaceController mSmartSpaceController;
private final ActivityStarter mActivityStarter;
private final String mSmartspaceTrampolineActivityComponent;
private SmartspaceTargetListener mSmartspaceTargetListener;
@@ -144,7 +139,7 @@ public class DreamWeatherComplication implements Complication {
@Named(DREAM_WEATHER_COMPLICATION_VIEW) TextView view,
@Named(SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT) String smartspaceTrampoline,
ActivityStarter activityStarter,
LockscreenSmartspaceController smartspaceController
DreamSmartspaceController smartspaceController
) {
super(view);
mActivityStarter = activityStarter;
@@ -192,12 +187,14 @@ public class DreamWeatherComplication implements Complication {
});
}
});
mSmartSpaceController.addListener(mSmartspaceTargetListener);
// We need to use an unfiltered listener here since weather is filtered from showing
// in the dream smartspace.
mSmartSpaceController.addUnfilteredListener(mSmartspaceTargetListener);
}
@Override
protected void onViewDetached() {
mSmartSpaceController.removeListener(mSmartspaceTargetListener);
mSmartSpaceController.removeUnfilteredListener(mSmartspaceTargetListener);
}
}
}

View File

@@ -19,6 +19,7 @@ package com.android.systemui.dreams.smartspace
import android.app.smartspace.SmartspaceConfig
import android.app.smartspace.SmartspaceManager
import android.app.smartspace.SmartspaceSession
import android.app.smartspace.SmartspaceTarget
import android.content.Context
import android.graphics.Color
import android.util.Log
@@ -66,7 +67,9 @@ class DreamSmartspaceController @Inject constructor(
private var targetFilter: SmartspaceTargetFilter? = optionalTargetFilter.orElse(null)
// A shadow copy of listeners is maintained to track whether the session should remain open.
private var listeners = mutableSetOf<BcSmartspaceDataPlugin.SmartspaceTargetListener>()
private var listeners = mutableSetOf<SmartspaceTargetListener>()
private var unfilteredListeners = mutableSetOf<SmartspaceTargetListener>()
// Smartspace can be used on multiple displays, such as when the user casts their screen
private var smartspaceViews = mutableSetOf<SmartspaceView>()
@@ -113,6 +116,7 @@ class DreamSmartspaceController @Inject constructor(
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
execution.assertIsMainThread()
onTargetsAvailableUnfiltered(targets)
val filteredTargets = targets.filter { targetFilter?.filterSmartspaceTarget(it) ?: true }
plugin?.onTargetsAvailable(filteredTargets)
}
@@ -137,7 +141,7 @@ class DreamSmartspaceController @Inject constructor(
private fun buildView(parent: ViewGroup): View? {
return if (plugin != null) {
var view = smartspaceViewComponentFactory.create(parent, plugin, stateChangeListener)
.getView()
.getView()
if (view !is View) {
return null
}
@@ -151,7 +155,8 @@ class DreamSmartspaceController @Inject constructor(
}
private fun hasActiveSessionListeners(): Boolean {
return smartspaceViews.isNotEmpty() || listeners.isNotEmpty()
return smartspaceViews.isNotEmpty() || listeners.isNotEmpty() ||
unfilteredListeners.isNotEmpty()
}
private fun connectSession() {
@@ -164,13 +169,15 @@ class DreamSmartspaceController @Inject constructor(
}
val newSession = smartspaceManager.createSmartspaceSession(
SmartspaceConfig.Builder(context, "dream").build())
SmartspaceConfig.Builder(context, "dream").build()
)
Log.d(TAG, "Starting smartspace session for dream")
newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
this.session = newSession
plugin.registerSmartspaceEventNotifier {
e -> session?.notifySmartspaceEvent(e)
e ->
session?.notifySmartspaceEvent(e)
}
reloadSmartspace()
@@ -218,4 +225,22 @@ class DreamSmartspaceController @Inject constructor(
private fun reloadSmartspace() {
session?.requestSmartspaceUpdate()
}
private fun onTargetsAvailableUnfiltered(targets: List<SmartspaceTarget>) {
unfilteredListeners.forEach { it.onSmartspaceTargetsUpdated(targets) }
}
/**
* Adds a listener for the raw, unfiltered list of smartspace targets. This should be used
* carefully, as it doesn't filter out targets which the user may not want shown.
*/
fun addUnfilteredListener(listener: SmartspaceTargetListener) {
unfilteredListeners.add(listener)
connectSession()
}
fun removeUnfilteredListener(listener: SmartspaceTargetListener) {
unfilteredListeners.remove(listener)
disconnect()
}
}

View File

@@ -17,18 +17,19 @@ package com.android.systemui.dreams.complication;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
import com.android.systemui.plugins.ActivityStarter;
import org.junit.Before;
import org.junit.Test;
@@ -39,12 +40,14 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamWeatherComplicationTest extends SysuiTestCase {
private static final String TRAMPOLINE_COMPONENT = "TestComponent";
@SuppressWarnings("HidingField")
@Mock
private Context mContext;
@Mock
private LockscreenSmartspaceController mSmartspaceController;
private DreamSmartspaceController mDreamSmartspaceController;
@Mock
private DreamOverlayStateController mDreamOverlayStateController;
@@ -58,22 +61,28 @@ public class DreamWeatherComplicationTest extends SysuiTestCase {
}
/**
* Ensures {@link DreamWeatherComplication} is only registered when it is available.
* Ensures {@link DreamWeatherComplication} is registered.
*/
@Test
public void testComplicationAvailability() {
when(mSmartspaceController.isEnabled()).thenReturn(false);
public void testComplicationRegistered() {
final DreamWeatherComplication.Registrant registrant =
new DreamWeatherComplication.Registrant(
mContext,
mSmartspaceController,
mDreamOverlayStateController,
mComplication);
registrant.start();
verify(mDreamOverlayStateController, never()).addComplication(any());
when(mSmartspaceController.isEnabled()).thenReturn(true);
registrant.start();
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
}
@Test
public void testGetUnfilteredTargets() {
final DreamWeatherComplication.DreamWeatherViewController controller =
new DreamWeatherComplication.DreamWeatherViewController(mock(
TextView.class), TRAMPOLINE_COMPONENT, mock(ActivityStarter.class),
mDreamSmartspaceController);
controller.onViewAttached();
verify(mDreamSmartspaceController).addUnfilteredListener(any());
controller.onViewDetached();
verify(mDreamSmartspaceController).removeUnfilteredListener(any());
}
}