diff --git a/libs/dream/lowlight/Android.bp b/libs/dream/lowlight/Android.bp new file mode 100644 index 0000000000000..5b5b0f07cabdc --- /dev/null +++ b/libs/dream/lowlight/Android.bp @@ -0,0 +1,47 @@ +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "low_light_dream_lib-sources", + srcs: [ + "src/**/*.java", + ], + path: "src", +} + +android_library { + name: "LowLightDreamLib", + srcs: [ + ":low_light_dream_lib-sources", + ], + resource_dirs: [ + "res", + ], + static_libs: [ + "androidx.arch.core_core-runtime", + "dagger2", + "jsr330", + ], + manifest: "AndroidManifest.xml", + plugins: ["dagger2-compiler"], +} diff --git a/libs/dream/lowlight/AndroidManifest.xml b/libs/dream/lowlight/AndroidManifest.xml new file mode 100644 index 0000000000000..a8d9526999431 --- /dev/null +++ b/libs/dream/lowlight/AndroidManifest.xml @@ -0,0 +1,18 @@ + + + + diff --git a/libs/dream/lowlight/res/values/config.xml b/libs/dream/lowlight/res/values/config.xml new file mode 100644 index 0000000000000..70fe0738a6f41 --- /dev/null +++ b/libs/dream/lowlight/res/values/config.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java new file mode 100644 index 0000000000000..5ecec4ddd1adf --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dream.lowlight; + +import static com.android.dream.lowlight.dagger.LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT; + +import android.annotation.IntDef; +import android.annotation.RequiresPermission; +import android.app.DreamManager; +import android.content.ComponentName; +import android.util.Log; + +import androidx.annotation.Nullable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * Maintains the ambient light mode of the environment the device is in, and sets a low light dream + * component, if present, as the system dream when the ambient light mode is low light. + * + * @hide + */ +public final class LowLightDreamManager { + private static final String TAG = "LowLightDreamManager"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "AMBIENT_LIGHT_MODE_" }, value = { + AMBIENT_LIGHT_MODE_UNKNOWN, + AMBIENT_LIGHT_MODE_REGULAR, + AMBIENT_LIGHT_MODE_LOW_LIGHT + }) + public @interface AmbientLightMode {} + + /** + * Constant for ambient light mode being unknown. + * @hide + */ + public static final int AMBIENT_LIGHT_MODE_UNKNOWN = 0; + + /** + * Constant for ambient light mode being regular / bright. + * @hide + */ + public static final int AMBIENT_LIGHT_MODE_REGULAR = 1; + + /** + * Constant for ambient light mode being low light / dim. + * @hide + */ + public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2; + + private final DreamManager mDreamManager; + + @Nullable + private final ComponentName mLowLightDreamComponent; + + private int mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN; + + @Inject + public LowLightDreamManager( + DreamManager dreamManager, + @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) { + mDreamManager = dreamManager; + mLowLightDreamComponent = lowLightDreamComponent; + } + + /** + * Sets the current ambient light mode. + * @hide + */ + @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) + public void setAmbientLightMode(@AmbientLightMode int ambientLightMode) { + if (mLowLightDreamComponent == null) { + if (DEBUG) { + Log.d(TAG, "ignore ambient light mode change because low light dream component " + + "is empty"); + } + return; + } + + if (mAmbientLightMode == ambientLightMode) { + return; + } + + if (DEBUG) { + Log.d(TAG, "ambient light mode changed from " + mAmbientLightMode + " to " + + ambientLightMode); + } + + mAmbientLightMode = ambientLightMode; + + mDreamManager.setSystemDreamComponent(mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT + ? mLowLightDreamComponent : null); + } +} diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java new file mode 100644 index 0000000000000..c183a04cb2f9b --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dream.lowlight.dagger; + +import android.app.DreamManager; +import android.content.ComponentName; +import android.content.Context; + +import androidx.annotation.Nullable; + +import com.android.dream.lowlight.R; + +import javax.inject.Named; + +import dagger.Module; +import dagger.Provides; + +/** + * Dagger module for low light dream. + * + * @hide + */ +@Module +public interface LowLightDreamModule { + String LOW_LIGHT_DREAM_COMPONENT = "low_light_dream_component"; + + /** + * Provides dream manager. + */ + @Provides + static DreamManager providesDreamManager(Context context) { + return context.getSystemService(DreamManager.class); + } + + /** + * Provides the component name of the low light dream, or null if not configured. + */ + @Provides + @Named(LOW_LIGHT_DREAM_COMPONENT) + @Nullable + static ComponentName providesLowLightDreamComponent(Context context) { + final String lowLightDreamComponent = context.getResources().getString( + R.string.config_lowLightDreamComponent); + return lowLightDreamComponent.isEmpty() ? null + : ComponentName.unflattenFromString(lowLightDreamComponent); + } +} diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp new file mode 100644 index 0000000000000..bd6f05eabac5c --- /dev/null +++ b/libs/dream/lowlight/tests/Android.bp @@ -0,0 +1,45 @@ +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "LowLightDreamTests", + srcs: [ + "**/*.java", + ], + static_libs: [ + "LowLightDreamLib", + "androidx.test.runner", + "androidx.test.rules", + "androidx.test.ext.junit", + "frameworks-base-testutils", + "junit", + "mockito-target-extended-minus-junit4", + "platform-test-annotations", + "testables", + "truth-prebuilt", + ], + libs: [ + "android.test.mock", + "android.test.base", + "android.test.runner", + ], + jni_libs: [ + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], +} diff --git a/libs/dream/lowlight/tests/AndroidManifest.xml b/libs/dream/lowlight/tests/AndroidManifest.xml new file mode 100644 index 0000000000000..abb71fb53b49e --- /dev/null +++ b/libs/dream/lowlight/tests/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/libs/dream/lowlight/tests/AndroidTest.xml b/libs/dream/lowlight/tests/AndroidTest.xml new file mode 100644 index 0000000000000..10800333add29 --- /dev/null +++ b/libs/dream/lowlight/tests/AndroidTest.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java new file mode 100644 index 0000000000000..91a170f7ae143 --- /dev/null +++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dream.lowlight; + +import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT; +import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR; +import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.app.DreamManager; +import android.content.ComponentName; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class LowLightDreamManagerTest { + @Mock + private DreamManager mDreamManager; + + @Mock + private ComponentName mDreamComponent; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void setAmbientLightMode_lowLight_setSystemDream() { + final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, + mDreamComponent); + + lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); + + verify(mDreamManager).setSystemDreamComponent(mDreamComponent); + } + + @Test + public void setAmbientLightMode_regularLight_clearSystemDream() { + final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, + mDreamComponent); + + lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR); + + verify(mDreamManager).setSystemDreamComponent(null); + } + + @Test + public void setAmbientLightMode_defaultUnknownMode_clearSystemDream() { + final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, + mDreamComponent); + + // Set to low light first. + lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); + clearInvocations(mDreamManager); + + // Return to default unknown mode. + lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN); + + verify(mDreamManager).setSystemDreamComponent(null); + } + + @Test + public void setAmbientLightMode_dreamComponentNotSet_doNothing() { + final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, + null /*dream component*/); + + lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); + + verify(mDreamManager, never()).setSystemDreamComponent(any()); + } +}