Merge "Do not allow complications when dream overlay is not enabled." into tm-qpr-dev

This commit is contained in:
Bryce Lee
2022-12-13 18:55:23 +00:00
committed by Android (Google) Code Review
6 changed files with 112 additions and 15 deletions

View File

@@ -16,6 +16,8 @@
package com.android.systemui.dreams; package com.android.systemui.dreams;
import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_SERVICE_COMPONENT;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@@ -35,6 +37,7 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
/** /**
* {@link DreamOverlayRegistrant} is responsible for telling system server that SystemUI should be * {@link DreamOverlayRegistrant} is responsible for telling system server that SystemUI should be
@@ -98,12 +101,13 @@ public class DreamOverlayRegistrant implements CoreStartable {
} }
@Inject @Inject
public DreamOverlayRegistrant(Context context, @Main Resources resources) { public DreamOverlayRegistrant(Context context, @Main Resources resources,
@Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent) {
mContext = context; mContext = context;
mResources = resources; mResources = resources;
mDreamManager = IDreamManager.Stub.asInterface( mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE)); ServiceManager.getService(DreamService.DREAM_SERVICE));
mOverlayServiceComponent = new ComponentName(mContext, DreamOverlayService.class); mOverlayServiceComponent = dreamOverlayServiceComponent;
} }
@Override @Override

View File

@@ -16,6 +16,8 @@
package com.android.systemui.dreams; package com.android.systemui.dreams;
import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_ENABLED;
import android.service.dreams.DreamService; import android.service.dreams.DreamService;
import android.util.Log; import android.util.Log;
@@ -37,6 +39,7 @@ import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
/** /**
* {@link DreamOverlayStateController} is the source of truth for Dream overlay configurations and * {@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 Executor mExecutor;
private final boolean mOverlayEnabled;
private final ArrayList<Callback> mCallbacks = new ArrayList<>(); private final ArrayList<Callback> mCallbacks = new ArrayList<>();
@Complication.ComplicationType @Complication.ComplicationType
@@ -94,14 +98,27 @@ public class DreamOverlayStateController implements
@VisibleForTesting @VisibleForTesting
@Inject @Inject
public DreamOverlayStateController(@Main Executor executor) { public DreamOverlayStateController(@Main Executor executor,
@Named(DREAM_OVERLAY_ENABLED) boolean overlayEnabled) {
mExecutor = executor; mExecutor = executor;
mOverlayEnabled = overlayEnabled;
if (DEBUG) {
Log.d(TAG, "Dream overlay enabled:" + mOverlayEnabled);
}
} }
/** /**
* Adds a complication to be included on the dream overlay. * Adds a complication to be included on the dream overlay.
*/ */
public void addComplication(Complication complication) { public void addComplication(Complication complication) {
if (!mOverlayEnabled) {
if (DEBUG) {
Log.d(TAG,
"Ignoring adding complication due to overlay disabled:" + complication);
}
return;
}
mExecutor.execute(() -> { mExecutor.execute(() -> {
if (mComplications.add(complication)) { if (mComplications.add(complication)) {
if (DEBUG) { if (DEBUG) {
@@ -116,6 +133,14 @@ public class DreamOverlayStateController implements
* Removes a complication from inclusion on the dream overlay. * Removes a complication from inclusion on the dream overlay.
*/ */
public void removeComplication(Complication complication) { public void removeComplication(Complication complication) {
if (!mOverlayEnabled) {
if (DEBUG) {
Log.d(TAG,
"Ignoring removing complication due to overlay disabled:" + complication);
}
return;
}
mExecutor.execute(() -> { mExecutor.execute(() -> {
if (mComplications.remove(complication)) { if (mComplications.remove(complication)) {
if (DEBUG) { if (DEBUG) {
@@ -193,7 +218,7 @@ public class DreamOverlayStateController implements
* @return {@code true} if overlay is active, {@code false} otherwise. * @return {@code true} if overlay is active, {@code false} otherwise.
*/ */
public boolean isOverlayActive() { public boolean isOverlayActive() {
return containsState(STATE_DREAM_OVERLAY_ACTIVE); return mOverlayEnabled && containsState(STATE_DREAM_OVERLAY_ACTIVE);
} }
/** /**

View File

@@ -138,19 +138,27 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
final ComplicationId id = complication.getId(); final ComplicationId id = complication.getId();
final Complication.ViewHolder viewHolder = complication.getComplication() final Complication.ViewHolder viewHolder = complication.getComplication()
.createView(complication); .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 // Complications to be added before dream entry animations are finished are set
// to invisible and are animated in. // to invisible and are animated in.
if (!mEntryAnimationsFinished) { if (!mEntryAnimationsFinished) {
viewHolder.getView().setVisibility(View.INVISIBLE); view.setVisibility(View.INVISIBLE);
} }
mComplications.put(id, viewHolder); mComplications.put(id, viewHolder);
if (viewHolder.getView().getParent() != null) { if (view.getParent() != null) {
Log.e(TAG, "View for complication " Log.e(TAG, "View for complication "
+ complication.getComplication().getClass() + complication.getComplication().getClass()
+ " already has a parent. Make sure not to reuse complication " + " already has a parent. Make sure not to reuse complication "
+ "views!"); + "views!");
} }
mLayoutEngine.addComplication(id, viewHolder.getView(), mLayoutEngine.addComplication(id, view,
viewHolder.getLayoutParams(), viewHolder.getCategory()); viewHolder.getLayoutParams(), viewHolder.getCategory());
}); });
} }

View File

@@ -16,7 +16,9 @@
package com.android.systemui.dreams.dagger; package com.android.systemui.dreams.dagger;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
import com.android.dream.lowlight.dagger.LowLightDreamModule; 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.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider; import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
import com.android.systemui.dreams.DreamOverlayService;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule; import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
import java.util.Optional; import java.util.Optional;
@@ -45,9 +48,34 @@ import dagger.Provides;
}) })
public interface DreamModule { public interface DreamModule {
String DREAM_ONLY_ENABLED_FOR_DOCK_USER = "dream_only_enabled_for_dock_user"; 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"; 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. * Provides an instance of the dream backend.
*/ */

View File

@@ -63,7 +63,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test @Test
public void testStateChange_overlayActive() { public void testStateChange_overlayActive() {
final DreamOverlayStateController stateController = new DreamOverlayStateController( final DreamOverlayStateController stateController = new DreamOverlayStateController(
mExecutor); mExecutor, true);
stateController.addCallback(mCallback); stateController.addCallback(mCallback);
stateController.setOverlayActive(true); stateController.setOverlayActive(true);
mExecutor.runAllReady(); mExecutor.runAllReady();
@@ -85,7 +85,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test @Test
public void testCallback() { public void testCallback() {
final DreamOverlayStateController stateController = new DreamOverlayStateController( final DreamOverlayStateController stateController = new DreamOverlayStateController(
mExecutor); mExecutor, true);
stateController.addCallback(mCallback); stateController.addCallback(mCallback);
// Add complication and verify callback is notified. // Add complication and verify callback is notified.
@@ -111,7 +111,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test @Test
public void testNotifyOnCallbackAdd() { public void testNotifyOnCallbackAdd() {
final DreamOverlayStateController stateController = final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor); new DreamOverlayStateController(mExecutor, true);
stateController.addComplication(mComplication); stateController.addComplication(mComplication);
mExecutor.runAllReady(); mExecutor.runAllReady();
@@ -122,10 +122,25 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
verify(mCallback, times(1)).onComplicationsChanged(); 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 @Test
public void testComplicationFilteringWhenShouldShowComplications() { public void testComplicationFilteringWhenShouldShowComplications() {
final DreamOverlayStateController stateController = final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor); new DreamOverlayStateController(mExecutor, true);
stateController.setShouldShowComplications(true); stateController.setShouldShowComplications(true);
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class); final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
@@ -165,7 +180,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test @Test
public void testComplicationFilteringWhenShouldHideComplications() { public void testComplicationFilteringWhenShouldHideComplications() {
final DreamOverlayStateController stateController = final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor); new DreamOverlayStateController(mExecutor, true);
stateController.setShouldShowComplications(true); stateController.setShouldShowComplications(true);
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class); final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
@@ -212,7 +227,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
public void testComplicationWithNoTypeNotFiltered() { public void testComplicationWithNoTypeNotFiltered() {
final Complication complication = Mockito.mock(Complication.class); final Complication complication = Mockito.mock(Complication.class);
final DreamOverlayStateController stateController = final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor); new DreamOverlayStateController(mExecutor, true);
stateController.addComplication(complication); stateController.addComplication(complication);
mExecutor.runAllReady(); mExecutor.runAllReady();
assertThat(stateController.getComplications(true).contains(complication)) assertThat(stateController.getComplications(true).contains(complication))
@@ -222,7 +237,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test @Test
public void testNotifyLowLightChanged() { public void testNotifyLowLightChanged() {
final DreamOverlayStateController stateController = final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor); new DreamOverlayStateController(mExecutor, true);
stateController.addCallback(mCallback); stateController.addCallback(mCallback);
mExecutor.runAllReady(); mExecutor.runAllReady();
@@ -238,7 +253,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
@Test @Test
public void testNotifyEntryAnimationsFinishedChanged() { public void testNotifyEntryAnimationsFinishedChanged() {
final DreamOverlayStateController stateController = final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor); new DreamOverlayStateController(mExecutor, true);
stateController.addCallback(mCallback); stateController.addCallback(mCallback);
mExecutor.runAllReady(); mExecutor.runAllReady();

View File

@@ -15,6 +15,8 @@
*/ */
package com.android.systemui.dreams.complication; 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.ArgumentMatchers.eq;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -138,6 +140,21 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
verify(mLayoutEngine).removeComplication(eq(mComplicationId)); 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 @Test
public void testNewComplicationsBeforeEntryAnimationsFinishSetToInvisible() { public void testNewComplicationsBeforeEntryAnimationsFinishSetToInvisible() {
final Observer<Collection<ComplicationViewModel>> observer = final Observer<Collection<ComplicationViewModel>> observer =