Do not allow complications when dream overlay is not enabled.
Complications are currently only hosted by the dream overlay. Dependent logic that listens on the DreamOverlayStateController for changes around complications should not be triggered when the dream overlay is not enabled. This changelist addresses this by preventing the DreamOverlayStateController from accepting complications when the overlay is not enabled (component wise). This change also null checks a complication view retrieved from the view holder before adding it to the layout. Test: atest DreamOverlayStateControllerTest Test: atest ComplicationHostViewControllerTest Fixes: 259859096 Change-Id: Ifa1b4a9da0070a949e422003d3fd4e9ca484a16e
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.systemui.dreams;
|
||||
|
||||
import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_SERVICE_COMPONENT;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -35,6 +37,7 @@ import com.android.systemui.CoreStartable;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* {@link DreamOverlayRegistrant} is responsible for telling system server that SystemUI should be
|
||||
@@ -98,12 +101,13 @@ public class DreamOverlayRegistrant implements CoreStartable {
|
||||
}
|
||||
|
||||
@Inject
|
||||
public DreamOverlayRegistrant(Context context, @Main Resources resources) {
|
||||
public DreamOverlayRegistrant(Context context, @Main Resources resources,
|
||||
@Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent) {
|
||||
mContext = context;
|
||||
mResources = resources;
|
||||
mDreamManager = IDreamManager.Stub.asInterface(
|
||||
ServiceManager.getService(DreamService.DREAM_SERVICE));
|
||||
mOverlayServiceComponent = new ComponentName(mContext, DreamOverlayService.class);
|
||||
mOverlayServiceComponent = dreamOverlayServiceComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.systemui.dreams;
|
||||
|
||||
import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_ENABLED;
|
||||
|
||||
import android.service.dreams.DreamService;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -37,6 +39,7 @@ import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* {@link DreamOverlayStateController} is the source of truth for Dream overlay configurations and
|
||||
@@ -83,6 +86,7 @@ public class DreamOverlayStateController implements
|
||||
}
|
||||
|
||||
private final Executor mExecutor;
|
||||
private final boolean mOverlayEnabled;
|
||||
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
|
||||
|
||||
@Complication.ComplicationType
|
||||
@@ -94,14 +98,27 @@ public class DreamOverlayStateController implements
|
||||
|
||||
@VisibleForTesting
|
||||
@Inject
|
||||
public DreamOverlayStateController(@Main Executor executor) {
|
||||
public DreamOverlayStateController(@Main Executor executor,
|
||||
@Named(DREAM_OVERLAY_ENABLED) boolean overlayEnabled) {
|
||||
mExecutor = executor;
|
||||
mOverlayEnabled = overlayEnabled;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Dream overlay enabled:" + mOverlayEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a complication to be included on the dream overlay.
|
||||
*/
|
||||
public void addComplication(Complication complication) {
|
||||
if (!mOverlayEnabled) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"Ignoring adding complication due to overlay disabled:" + complication);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mExecutor.execute(() -> {
|
||||
if (mComplications.add(complication)) {
|
||||
if (DEBUG) {
|
||||
@@ -116,6 +133,14 @@ public class DreamOverlayStateController implements
|
||||
* Removes a complication from inclusion on the dream overlay.
|
||||
*/
|
||||
public void removeComplication(Complication complication) {
|
||||
if (!mOverlayEnabled) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"Ignoring removing complication due to overlay disabled:" + complication);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mExecutor.execute(() -> {
|
||||
if (mComplications.remove(complication)) {
|
||||
if (DEBUG) {
|
||||
@@ -193,7 +218,7 @@ public class DreamOverlayStateController implements
|
||||
* @return {@code true} if overlay is active, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isOverlayActive() {
|
||||
return containsState(STATE_DREAM_OVERLAY_ACTIVE);
|
||||
return mOverlayEnabled && containsState(STATE_DREAM_OVERLAY_ACTIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -138,19 +138,27 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
|
||||
final ComplicationId id = complication.getId();
|
||||
final Complication.ViewHolder viewHolder = complication.getComplication()
|
||||
.createView(complication);
|
||||
|
||||
final View view = viewHolder.getView();
|
||||
|
||||
if (view == null) {
|
||||
Log.e(TAG, "invalid complication view. null view supplied by ViewHolder");
|
||||
return;
|
||||
}
|
||||
|
||||
// Complications to be added before dream entry animations are finished are set
|
||||
// to invisible and are animated in.
|
||||
if (!mEntryAnimationsFinished) {
|
||||
viewHolder.getView().setVisibility(View.INVISIBLE);
|
||||
view.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
mComplications.put(id, viewHolder);
|
||||
if (viewHolder.getView().getParent() != null) {
|
||||
if (view.getParent() != null) {
|
||||
Log.e(TAG, "View for complication "
|
||||
+ complication.getComplication().getClass()
|
||||
+ " already has a parent. Make sure not to reuse complication "
|
||||
+ "views!");
|
||||
}
|
||||
mLayoutEngine.addComplication(id, viewHolder.getView(),
|
||||
mLayoutEngine.addComplication(id, view,
|
||||
viewHolder.getLayoutParams(), viewHolder.getCategory());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package com.android.systemui.dreams.dagger;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import com.android.dream.lowlight.dagger.LowLightDreamModule;
|
||||
@@ -24,6 +26,7 @@ import com.android.settingslib.dream.DreamBackend;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
|
||||
import com.android.systemui.dreams.DreamOverlayService;
|
||||
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -45,9 +48,34 @@ import dagger.Provides;
|
||||
})
|
||||
public interface DreamModule {
|
||||
String DREAM_ONLY_ENABLED_FOR_DOCK_USER = "dream_only_enabled_for_dock_user";
|
||||
String DREAM_OVERLAY_SERVICE_COMPONENT = "dream_overlay_service_component";
|
||||
String DREAM_OVERLAY_ENABLED = "dream_overlay_enabled";
|
||||
|
||||
String DREAM_SUPPORTED = "dream_supported";
|
||||
|
||||
/**
|
||||
* Provides the dream component
|
||||
*/
|
||||
@Provides
|
||||
@Named(DREAM_OVERLAY_SERVICE_COMPONENT)
|
||||
static ComponentName providesDreamOverlayService(Context context) {
|
||||
return new ComponentName(context, DreamOverlayService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides whether dream overlay is enabled.
|
||||
*/
|
||||
@Provides
|
||||
@Named(DREAM_OVERLAY_ENABLED)
|
||||
static Boolean providesDreamOverlayEnabled(PackageManager packageManager,
|
||||
@Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName component) {
|
||||
try {
|
||||
return packageManager.getServiceInfo(component, PackageManager.GET_META_DATA).enabled;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an instance of the dream backend.
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testStateChange_overlayActive() {
|
||||
final DreamOverlayStateController stateController = new DreamOverlayStateController(
|
||||
mExecutor);
|
||||
mExecutor, true);
|
||||
stateController.addCallback(mCallback);
|
||||
stateController.setOverlayActive(true);
|
||||
mExecutor.runAllReady();
|
||||
@@ -85,7 +85,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testCallback() {
|
||||
final DreamOverlayStateController stateController = new DreamOverlayStateController(
|
||||
mExecutor);
|
||||
mExecutor, true);
|
||||
stateController.addCallback(mCallback);
|
||||
|
||||
// Add complication and verify callback is notified.
|
||||
@@ -111,7 +111,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testNotifyOnCallbackAdd() {
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor);
|
||||
new DreamOverlayStateController(mExecutor, true);
|
||||
|
||||
stateController.addComplication(mComplication);
|
||||
mExecutor.runAllReady();
|
||||
@@ -122,10 +122,25 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
verify(mCallback, times(1)).onComplicationsChanged();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifyOnCallbackAddOverlayDisabled() {
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor, false);
|
||||
|
||||
stateController.addComplication(mComplication);
|
||||
mExecutor.runAllReady();
|
||||
|
||||
// Verify callback occurs on add when an overlay is already present.
|
||||
stateController.addCallback(mCallback);
|
||||
mExecutor.runAllReady();
|
||||
verify(mCallback, never()).onComplicationsChanged();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testComplicationFilteringWhenShouldShowComplications() {
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor);
|
||||
new DreamOverlayStateController(mExecutor, true);
|
||||
stateController.setShouldShowComplications(true);
|
||||
|
||||
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
|
||||
@@ -165,7 +180,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testComplicationFilteringWhenShouldHideComplications() {
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor);
|
||||
new DreamOverlayStateController(mExecutor, true);
|
||||
stateController.setShouldShowComplications(true);
|
||||
|
||||
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
|
||||
@@ -212,7 +227,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
public void testComplicationWithNoTypeNotFiltered() {
|
||||
final Complication complication = Mockito.mock(Complication.class);
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor);
|
||||
new DreamOverlayStateController(mExecutor, true);
|
||||
stateController.addComplication(complication);
|
||||
mExecutor.runAllReady();
|
||||
assertThat(stateController.getComplications(true).contains(complication))
|
||||
@@ -222,7 +237,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testNotifyLowLightChanged() {
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor);
|
||||
new DreamOverlayStateController(mExecutor, true);
|
||||
|
||||
stateController.addCallback(mCallback);
|
||||
mExecutor.runAllReady();
|
||||
@@ -238,7 +253,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testNotifyEntryAnimationsFinishedChanged() {
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor);
|
||||
new DreamOverlayStateController(mExecutor, true);
|
||||
|
||||
stateController.addCallback(mCallback);
|
||||
mExecutor.runAllReady();
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.systemui.dreams.complication;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -138,6 +140,21 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
|
||||
verify(mLayoutEngine).removeComplication(eq(mComplicationId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformedComplicationAddition() {
|
||||
final Observer<Collection<ComplicationViewModel>> observer =
|
||||
captureComplicationViewModelsObserver();
|
||||
|
||||
// Add a complication and ensure it is added to the view.
|
||||
final HashSet<ComplicationViewModel> complications = new HashSet<>(
|
||||
Collections.singletonList(mComplicationViewModel));
|
||||
when(mViewHolder.getView()).thenReturn(null);
|
||||
observer.onChanged(complications);
|
||||
|
||||
verify(mLayoutEngine, never()).addComplication(any(), any(), any(), anyInt());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewComplicationsBeforeEntryAnimationsFinishSetToInvisible() {
|
||||
final Observer<Collection<ComplicationViewModel>> observer =
|
||||
|
||||
Reference in New Issue
Block a user