summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java190
-rw-r--r--core/java/android/os/IpcDataCache.java6
-rw-r--r--core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java97
-rw-r--r--media/java/android/media/quality/AmbientBacklightEvent.aidl19
-rw-r--r--media/java/android/media/quality/AmbientBacklightEvent.java136
-rw-r--r--media/java/android/media/quality/AmbientBacklightMetadata.aidl19
-rw-r--r--media/java/android/media/quality/AmbientBacklightMetadata.java127
-rw-r--r--media/java/android/media/quality/AmbientBacklightSettings.aidl19
-rw-r--r--media/java/android/media/quality/AmbientBacklightSettings.java203
-rw-r--r--media/java/android/media/quality/IAmbientBacklightCallback.aidl24
-rw-r--r--media/java/android/media/quality/IMediaQualityManager.aidl8
-rw-r--r--media/java/android/media/quality/MediaQualityManager.java112
-rw-r--r--services/core/java/com/android/server/media/quality/MediaQualityService.java13
13 files changed, 908 insertions, 65 deletions
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index a39cf84a4ebe..038dcdb7efc9 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -17,6 +17,7 @@
package android.app;
import static android.text.TextUtils.formatSimple;
+import static com.android.internal.util.Preconditions.checkArgumentPositive;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,6 +41,7 @@ import com.android.internal.os.BackgroundThread;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
+import dalvik.annotation.optimization.NeverCompile;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
@@ -201,6 +203,23 @@ public class PropertyInvalidatedCache<Query, Result> {
}
/**
+ * The list of known and legal modules. The list is not sorted.
+ */
+ private static final String[] sValidModule = {
+ MODULE_SYSTEM, MODULE_BLUETOOTH, MODULE_TELEPHONY, MODULE_TEST,
+ };
+
+ /**
+ * Verify that the module string is in the legal list. Throw if it is not.
+ */
+ private static void throwIfInvalidModule(@NonNull String name) {
+ for (int i = 0; i < sValidModule.length; i++) {
+ if (sValidModule[i].equals(name)) return;
+ }
+ throw new IllegalArgumentException("invalid module: " + name);
+ }
+
+ /**
* All legal keys start with one of the following strings.
*/
private static final String[] sValidKeyPrefix = {
@@ -254,8 +273,11 @@ public class PropertyInvalidatedCache<Query, Result> {
// written to global store.
private static final int NONCE_BYPASS = 3;
+ // The largest reserved nonce value. Update this whenever a reserved nonce is added.
+ private static final int MAX_RESERVED_NONCE = NONCE_BYPASS;
+
private static boolean isReservedNonce(long n) {
- return n >= NONCE_UNSET && n <= NONCE_BYPASS;
+ return n >= NONCE_UNSET && n <= MAX_RESERVED_NONCE;
}
/**
@@ -293,7 +315,7 @@ public class PropertyInvalidatedCache<Query, Result> {
private long mMisses = 0;
@GuardedBy("mLock")
- private long[] mSkips = new long[]{ 0, 0, 0, 0 };
+ private long[] mSkips = new long[MAX_RESERVED_NONCE + 1];
@GuardedBy("mLock")
private long mMissOverflow = 0;
@@ -854,6 +876,73 @@ public class PropertyInvalidatedCache<Query, Result> {
}
/**
+ * A public argument builder to configure cache behavior. The root instance requires a
+ * module; this is immutable. New instances are created with member methods. It is important
+ * to note that the member methods create new instances: they do not modify 'this'. The api
+ * is allowed to be null in the record constructor to facility reuse of Args instances.
+ * @hide
+ */
+ public static record Args(@NonNull String mModule, @Nullable String mApi, int mMaxEntries) {
+
+ // Validation: the module must be one of the known module strings and the maxEntries must
+ // be positive.
+ public Args {
+ throwIfInvalidModule(mModule);
+ checkArgumentPositive(mMaxEntries, "max cache size must be positive");
+ }
+
+ // The base constructor must include the module. Modules do not change in a source file,
+ // so even if the Args is reused, the module will not/should not change. The api is null,
+ // which is not legal, but there is no reasonable default. Clients must call the api
+ // method to set the field properly.
+ public Args(@NonNull String module) {
+ this(module, /* api */ null, /* maxEntries */ 32);
+ }
+
+ public Args api(@NonNull String api) {
+ return new Args(mModule, api, mMaxEntries);
+ }
+
+ public Args maxEntries(int val) {
+ return new Args(mModule, mApi, val);
+ }
+ }
+
+ /**
+ * Make a new property invalidated cache. The key is computed from the module and api
+ * parameters.
+ *
+ * @param args The cache configuration.
+ * @param cacheName Name of this cache in debug and dumpsys
+ * @param computer The code to compute values that are not in the cache.
+ * @hide
+ */
+ public PropertyInvalidatedCache(@NonNull Args args, @NonNull String cacheName,
+ @Nullable QueryHandler<Query, Result> computer) {
+ mPropertyName = createPropertyName(args.mModule, args.mApi);
+ mCacheName = cacheName;
+ mNonce = getNonceHandler(mPropertyName);
+ mMaxEntries = args.mMaxEntries;
+ mCache = createMap();
+ mComputer = (computer != null) ? computer : new DefaultComputer<>(this);
+ registerCache();
+ }
+
+ /**
+ * Burst a property name into module and api. Throw if the key is invalid. This method is
+ * used in to transition legacy cache constructors to the args constructor.
+ */
+ private static Args parseProperty(@NonNull String name) {
+ throwIfInvalidCacheKey(name);
+ // Strip off the leading well-known prefix.
+ String base = name.substring(CACHE_KEY_PREFIX.length() + 1);
+ int dot = base.indexOf(".");
+ String module = base.substring(0, dot);
+ String api = base.substring(dot + 1);
+ return new Args(module).api(api);
+ }
+
+ /**
* Make a new property invalidated cache. This constructor names the cache after the
* property name. New clients should prefer the constructor that takes an explicit
* cache name.
@@ -867,7 +956,7 @@ public class PropertyInvalidatedCache<Query, Result> {
* @hide
*/
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
- this(maxEntries, propertyName, propertyName);
+ this(parseProperty(propertyName).maxEntries(maxEntries), propertyName, null);
}
/**
@@ -883,13 +972,7 @@ public class PropertyInvalidatedCache<Query, Result> {
*/
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName,
@NonNull String cacheName) {
- mPropertyName = propertyName;
- mCacheName = cacheName;
- mNonce = getNonceHandler(mPropertyName);
- mMaxEntries = maxEntries;
- mComputer = new DefaultComputer<>(this);
- mCache = createMap();
- registerCache();
+ this(parseProperty(propertyName).maxEntries(maxEntries), cacheName, null);
}
/**
@@ -907,13 +990,7 @@ public class PropertyInvalidatedCache<Query, Result> {
@TestApi
public PropertyInvalidatedCache(int maxEntries, @NonNull String module, @NonNull String api,
@NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
- mPropertyName = createPropertyName(module, api);
- mCacheName = cacheName;
- mNonce = getNonceHandler(mPropertyName);
- mMaxEntries = maxEntries;
- mComputer = computer;
- mCache = createMap();
- registerCache();
+ this(new Args(module).maxEntries(maxEntries).api(api), cacheName, computer);
}
// Create a map. This should be called only from the constructor.
@@ -1181,7 +1258,8 @@ public class PropertyInvalidatedCache<Query, Result> {
public @Nullable Result query(@NonNull Query query) {
// Let access to mDisabled race: it's atomic anyway.
long currentNonce = (!isDisabled()) ? getCurrentNonce() : NONCE_DISABLED;
- if (bypass(query)) {
+ if (!isReservedNonce(currentNonce)
+ && bypass(query)) {
currentNonce = NONCE_BYPASS;
}
for (;;) {
@@ -1649,54 +1727,62 @@ public class PropertyInvalidatedCache<Query, Result> {
return false;
}
- /**
- * helper method to check if dump should be skipped due to zero values
- * @param args takes command arguments to check if -brief is present
- * @return True if dump should be skipped
- */
- private boolean skipDump(String[] args) {
- for (String a : args) {
- if (a.equals(BRIEF)) {
- return (mSkips[NONCE_CORKED] + mSkips[NONCE_UNSET] + mSkips[NONCE_DISABLED]
- + mSkips[NONCE_BYPASS] + mHits + mMisses) == 0;
- }
+ @GuardedBy("mLock")
+ private long getSkipsLocked() {
+ int sum = 0;
+ for (int i = 0; i < mSkips.length; i++) {
+ sum += mSkips[i];
}
- return false;
+ return sum;
}
+ // Return true if this cache has had any activity. If the hits, misses, and skips are all
+ // zero then the client never tried to use the cache.
+ private boolean isActive() {
+ synchronized (mLock) {
+ return mHits + mMisses + getSkipsLocked() > 0;
+ }
+ }
+
+ @NeverCompile
private void dumpContents(PrintWriter pw, boolean detailed, String[] args) {
// If the user has requested specific caches and this is not one of them, return
// immediately.
if (detailed && !showDetailed(args)) {
return;
}
+ // Does the user want brief output?
+ boolean brief = false;
+ for (String a : args) brief |= a.equals(BRIEF);
NonceHandler.Stats stats = mNonce.getStats();
synchronized (mLock) {
- if (!skipDump(args)) {
- pw.println(formatSimple(" Cache Name: %s", cacheName()));
- pw.println(formatSimple(" Property: %s", mPropertyName));
- final long skips =
- mSkips[NONCE_CORKED] + mSkips[NONCE_UNSET] + mSkips[NONCE_DISABLED]
- + mSkips[NONCE_BYPASS];
- pw.println(formatSimple(
- " Hits: %d, Misses: %d, Skips: %d, Clears: %d",
- mHits, mMisses, skips, mClears));
- pw.println(formatSimple(
- " Skip-corked: %d, Skip-unset: %d, Skip-bypass: %d, Skip-other: %d",
- mSkips[NONCE_CORKED], mSkips[NONCE_UNSET],
- mSkips[NONCE_BYPASS], mSkips[NONCE_DISABLED]));
- pw.println(formatSimple(
- " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d",
- mLastSeenNonce, stats.invalidated, stats.corkedInvalidates));
- pw.println(formatSimple(
- " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d",
- mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow));
- pw.println(formatSimple(" Enabled: %s", mDisabled ? "false" : "true"));
- pw.println("");
+ if (brief && !isActive()) {
+ return;
}
+ pw.println(formatSimple(" Cache Name: %s", cacheName()));
+ pw.println(formatSimple(" Property: %s", mPropertyName));
+ pw.println(formatSimple(
+ " Hits: %d, Misses: %d, Skips: %d, Clears: %d",
+ mHits, mMisses, getSkipsLocked(), mClears));
+
+ // Print all the skip reasons.
+ pw.format(" Skip-%s: %d", sNonceName[0], mSkips[0]);
+ for (int i = 1; i < mSkips.length; i++) {
+ pw.format(", Skip-%s: %d", sNonceName[i], mSkips[i]);
+ }
+ pw.println();
+
+ pw.println(formatSimple(
+ " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d",
+ mLastSeenNonce, stats.invalidated, stats.corkedInvalidates));
+ pw.println(formatSimple(
+ " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d",
+ mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow));
+ pw.println(formatSimple(" Enabled: %s", mDisabled ? "false" : "true"));
+
// No specific cache was requested. This is the default, and no details
// should be dumped.
if (!detailed) {
@@ -1723,6 +1809,7 @@ public class PropertyInvalidatedCache<Query, Result> {
* specific caches (selection is by cache name or property name); if these switches
* are used then the output includes both cache statistics and cache entries.
*/
+ @NeverCompile
private static void dumpCacheInfo(@NonNull PrintWriter pw, @NonNull String[] args) {
if (!sEnabled) {
pw.println(" Caching is disabled in this process.");
@@ -1755,6 +1842,7 @@ public class PropertyInvalidatedCache<Query, Result> {
* are used then the output includes both cache statistics and cache entries.
* @hide
*/
+ @NeverCompile
public static void dumpCacheInfo(@NonNull ParcelFileDescriptor pfd, @NonNull String[] args) {
// Create a PrintWriter that uses a byte array. The code can safely write to
// this array without fear of blocking. The completed byte array will be sent
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index 7875c23be038..8db1567336d3 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -23,6 +23,7 @@ import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.PropertyInvalidatedCache;
+import android.app.PropertyInvalidatedCache.Args;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -341,7 +342,7 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
public IpcDataCache(int maxEntries, @NonNull @IpcDataCacheModule String module,
@NonNull String api, @NonNull String cacheName,
@NonNull QueryHandler<Query, Result> computer) {
- super(maxEntries, module, api, cacheName, computer);
+ super(new Args(module).maxEntries(maxEntries).api(api), cacheName, computer);
}
/**
@@ -563,7 +564,8 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
* @hide
*/
public IpcDataCache(@NonNull Config config, @NonNull QueryHandler<Query, Result> computer) {
- super(config.maxEntries(), config.module(), config.api(), config.name(), computer);
+ super(new Args(config.module()).maxEntries(config.maxEntries()).api(config.api()),
+ config.name(), computer);
}
/**
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index c2d8f9129e2c..da1fffa0fac4 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -17,6 +17,9 @@
package android.app;
import static android.app.PropertyInvalidatedCache.NONCE_UNSET;
+import static android.app.PropertyInvalidatedCache.MODULE_BLUETOOTH;
+import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;
+import static android.app.PropertyInvalidatedCache.MODULE_TEST;
import static android.app.PropertyInvalidatedCache.NonceStore.INVALID_NONCE_INDEX;
import static com.android.internal.os.Flags.FLAG_APPLICATION_SHARED_MEMORY_ENABLED;
@@ -27,6 +30,8 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.PropertyInvalidatedCache.Args;
+import android.annotation.SuppressLint;
import com.android.internal.os.ApplicationSharedMemory;
import android.platform.test.annotations.IgnoreUnderRavenwood;
@@ -57,7 +62,7 @@ public class PropertyInvalidatedCacheTests {
DeviceFlagsValueProvider.createCheckFlagsRule();
// Configuration for creating caches
- private static final String MODULE = PropertyInvalidatedCache.MODULE_TEST;
+ private static final String MODULE = MODULE_TEST;
private static final String API = "testApi";
// This class is a proxy for binder calls. It contains a counter that increments
@@ -245,6 +250,12 @@ public class PropertyInvalidatedCacheTests {
mQuery = query;
}
+ // Create a cache from the args. The name of the cache is the api.
+ TestCache(Args args, TestQuery query) {
+ super(args, args.mApi(), query);
+ mQuery = query;
+ }
+
public int getRecomputeCount() {
return mQuery.getRecomputeCount();
}
@@ -374,14 +385,11 @@ public class PropertyInvalidatedCacheTests {
@Test
public void testPropertyNames() {
String n1;
- n1 = PropertyInvalidatedCache.createPropertyName(
- PropertyInvalidatedCache.MODULE_SYSTEM, "getPackageInfo");
+ n1 = PropertyInvalidatedCache.createPropertyName(MODULE_SYSTEM, "getPackageInfo");
assertEquals(n1, "cache_key.system_server.get_package_info");
- n1 = PropertyInvalidatedCache.createPropertyName(
- PropertyInvalidatedCache.MODULE_SYSTEM, "get_package_info");
+ n1 = PropertyInvalidatedCache.createPropertyName(MODULE_SYSTEM, "get_package_info");
assertEquals(n1, "cache_key.system_server.get_package_info");
- n1 = PropertyInvalidatedCache.createPropertyName(
- PropertyInvalidatedCache.MODULE_BLUETOOTH, "getState");
+ n1 = PropertyInvalidatedCache.createPropertyName(MODULE_BLUETOOTH, "getState");
assertEquals(n1, "cache_key.bluetooth.get_state");
}
@@ -391,7 +399,7 @@ public class PropertyInvalidatedCacheTests {
reason = "SystemProperties doesn't have permission check")
public void testPermissionFailure() {
// Create a cache that will write a system nonce.
- TestCache sysCache = new TestCache(PropertyInvalidatedCache.MODULE_SYSTEM, "mode1");
+ TestCache sysCache = new TestCache(MODULE_SYSTEM, "mode1");
try {
// Invalidate the cache, which writes the system property. There must be a permission
// failure.
@@ -407,7 +415,7 @@ public class PropertyInvalidatedCacheTests {
@Test
public void testTestMode() {
// Create a cache that will write a system nonce.
- TestCache sysCache = new TestCache(PropertyInvalidatedCache.MODULE_SYSTEM, "mode1");
+ TestCache sysCache = new TestCache(MODULE_SYSTEM, "mode1");
sysCache.testPropertyName();
// Invalidate the cache. This must succeed because the property has been marked for
@@ -416,7 +424,7 @@ public class PropertyInvalidatedCacheTests {
// Create a cache that uses MODULE_TEST. Invalidation succeeds whether or not the
// property is tagged as being tested.
- TestCache testCache = new TestCache(PropertyInvalidatedCache.MODULE_TEST, "mode2");
+ TestCache testCache = new TestCache(MODULE_TEST, "mode2");
testCache.invalidateCache();
testCache.testPropertyName();
testCache.invalidateCache();
@@ -432,7 +440,7 @@ public class PropertyInvalidatedCacheTests {
// The expected exception.
}
// Configuring a property for testing must fail if test mode is false.
- TestCache cache2 = new TestCache(PropertyInvalidatedCache.MODULE_SYSTEM, "mode3");
+ TestCache cache2 = new TestCache(MODULE_SYSTEM, "mode3");
try {
cache2.testPropertyName();
fail("expected an IllegalStateException");
@@ -444,6 +452,34 @@ public class PropertyInvalidatedCacheTests {
PropertyInvalidatedCache.setTestMode(true);
}
+ // Test the Args-style constructor.
+ @Test
+ public void testArgsConstructor() {
+ // Create a cache with a maximum of four entries.
+ TestCache cache = new TestCache(new Args(MODULE_TEST).api("init1").maxEntries(4),
+ new TestQuery());
+
+ cache.invalidateCache();
+ for (int i = 1; i <= 4; i++) {
+ assertEquals("foo" + i, cache.query(i));
+ assertEquals(i, cache.getRecomputeCount());
+ }
+ // Everything is in the cache. The recompute count must not increase.
+ for (int i = 1; i <= 4; i++) {
+ assertEquals("foo" + i, cache.query(i));
+ assertEquals(4, cache.getRecomputeCount());
+ }
+ // Overflow the max entries. The recompute count increases by one.
+ assertEquals("foo5", cache.query(5));
+ assertEquals(5, cache.getRecomputeCount());
+ // The oldest entry (1) has been evicted. Iterating through the first four entries will
+ // sequentially evict them all because the loop is proceeding oldest to newest.
+ for (int i = 1; i <= 4; i++) {
+ assertEquals("foo" + i, cache.query(i));
+ assertEquals(5+i, cache.getRecomputeCount());
+ }
+ }
+
// Verify the behavior of shared memory nonce storage. This does not directly test the cache
// storing nonces in shared memory.
@RequiresFlagsEnabled(FLAG_APPLICATION_SHARED_MEMORY_ENABLED)
@@ -495,4 +531,43 @@ public class PropertyInvalidatedCacheTests {
shmem.close();
}
+
+ // Verify that an invalid module causes an exception.
+ private void testInvalidModule(String module) {
+ try {
+ @SuppressLint("UnusedVariable")
+ Args arg = new Args(module);
+ fail("expected an invalid module exception: module=" + module);
+ } catch (IllegalArgumentException e) {
+ // Expected exception.
+ }
+ }
+
+ // Test various instantiation errors. The good path is tested in other methods.
+ @Test
+ public void testArgumentErrors() {
+ // Verify that an illegal module throws an exception.
+ testInvalidModule(MODULE_SYSTEM.substring(0, MODULE_SYSTEM.length() - 1));
+ testInvalidModule(MODULE_SYSTEM + "x");
+ testInvalidModule("mymodule");
+
+ // Verify that a negative max entries throws.
+ Args arg = new Args(MODULE_SYSTEM);
+ try {
+ arg.maxEntries(0);
+ fail("expected an invalid maxEntries exception");
+ } catch (IllegalArgumentException e) {
+ // Expected exception.
+ }
+
+ // Verify that creating a cache with an invalid property string throws.
+ try {
+ final String badKey = "cache_key.volume_list";
+ @SuppressLint("UnusedVariable")
+ var cache = new PropertyInvalidatedCache<Integer, Void>(4, badKey);
+ fail("expected bad property exception: prop=" + badKey);
+ } catch (IllegalArgumentException e) {
+ // Expected exception.
+ }
+ }
}
diff --git a/media/java/android/media/quality/AmbientBacklightEvent.aidl b/media/java/android/media/quality/AmbientBacklightEvent.aidl
new file mode 100644
index 000000000000..174cd461e846
--- /dev/null
+++ b/media/java/android/media/quality/AmbientBacklightEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 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 android.media.quality;
+
+parcelable AmbientBacklightEvent;
diff --git a/media/java/android/media/quality/AmbientBacklightEvent.java b/media/java/android/media/quality/AmbientBacklightEvent.java
new file mode 100644
index 000000000000..3bc6b86c0615
--- /dev/null
+++ b/media/java/android/media/quality/AmbientBacklightEvent.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 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 android.media.quality;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public final class AmbientBacklightEvent implements Parcelable {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({AMBIENT_BACKLIGHT_EVENT_ENABLED, AMBIENT_BACKLIGHT_EVENT_DISABLED,
+ AMBIENT_BACKLIGHT_EVENT_METADATA,
+ AMBIENT_BACKLIGHT_EVENT_INTERRUPTED})
+ public @interface AmbientBacklightEventTypes {}
+
+ /**
+ * Event type for ambient backlight events. The ambient backlight is enabled.
+ */
+ public static final int AMBIENT_BACKLIGHT_EVENT_ENABLED = 1;
+
+ /**
+ * Event type for ambient backlight events. The ambient backlight is disabled.
+ */
+ public static final int AMBIENT_BACKLIGHT_EVENT_DISABLED = 2;
+
+ /**
+ * Event type for ambient backlight events. The ambient backlight metadata is
+ * available.
+ */
+ public static final int AMBIENT_BACKLIGHT_EVENT_METADATA = 3;
+
+ /**
+ * Event type for ambient backlight events. The ambient backlight event is preempted by another
+ * application.
+ */
+ public static final int AMBIENT_BACKLIGHT_EVENT_INTERRUPTED = 4;
+
+ private final int mEventType;
+ @Nullable
+ private final AmbientBacklightMetadata mMetadata;
+
+ public AmbientBacklightEvent(int eventType,
+ @Nullable AmbientBacklightMetadata metadata) {
+ mEventType = eventType;
+ mMetadata = metadata;
+ }
+
+ private AmbientBacklightEvent(Parcel in) {
+ mEventType = in.readInt();
+ mMetadata = in.readParcelable(AmbientBacklightMetadata.class.getClassLoader());
+ }
+
+ public int getEventType() {
+ return mEventType;
+ }
+
+ @Nullable
+ public AmbientBacklightMetadata getMetadata() {
+ return mMetadata;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mEventType);
+ dest.writeParcelable(mMetadata, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Parcelable.Creator<AmbientBacklightEvent> CREATOR =
+ new Parcelable.Creator<AmbientBacklightEvent>() {
+ public AmbientBacklightEvent createFromParcel(Parcel in) {
+ return new AmbientBacklightEvent(in);
+ }
+
+ public AmbientBacklightEvent[] newArray(int size) {
+ return new AmbientBacklightEvent[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (!(obj instanceof AmbientBacklightEvent)) {
+ return false;
+ }
+
+ AmbientBacklightEvent other = (AmbientBacklightEvent) obj;
+ return mEventType == other.mEventType
+ && Objects.equals(mMetadata, other.mMetadata);
+ }
+
+ @Override
+ public int hashCode() {
+ return mEventType * 31 + (mMetadata != null ? mMetadata.hashCode() : 0);
+ }
+
+ @Override
+ public String toString() {
+ return "AmbientBacklightEvent{"
+ + "mEventType=" + mEventType
+ + ", mMetadata=" + mMetadata
+ + '}';
+ }
+}
diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.aidl b/media/java/android/media/quality/AmbientBacklightMetadata.aidl
new file mode 100644
index 000000000000..b95a474fbf90
--- /dev/null
+++ b/media/java/android/media/quality/AmbientBacklightMetadata.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 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 android.media.quality;
+
+parcelable AmbientBacklightMetadata; \ No newline at end of file
diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.java b/media/java/android/media/quality/AmbientBacklightMetadata.java
new file mode 100644
index 000000000000..fc779348de11
--- /dev/null
+++ b/media/java/android/media/quality/AmbientBacklightMetadata.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2024 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 android.media.quality;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+public class AmbientBacklightMetadata implements Parcelable {
+ @NonNull
+ private final String mPackageName;
+ private final int mCompressAlgorithm;
+ private final int mSource;
+ private final int mColorFormat;
+ private final int mHorizontalZonesNumber;
+ private final int mVerticalZonesNumber;
+ @NonNull
+ private final int[] mZonesColors;
+
+ public AmbientBacklightMetadata(@NonNull String packageName, int compressAlgorithm,
+ int source, int colorFormat, int horizontalZonesNumber, int verticalZonesNumber,
+ @NonNull int[] zonesColors) {
+ mPackageName = packageName;
+ mCompressAlgorithm = compressAlgorithm;
+ mSource = source;
+ mColorFormat = colorFormat;
+ mHorizontalZonesNumber = horizontalZonesNumber;
+ mVerticalZonesNumber = verticalZonesNumber;
+ mZonesColors = zonesColors;
+ }
+
+ private AmbientBacklightMetadata(Parcel in) {
+ mPackageName = in.readString();
+ mCompressAlgorithm = in.readInt();
+ mSource = in.readInt();
+ mColorFormat = in.readInt();
+ mHorizontalZonesNumber = in.readInt();
+ mVerticalZonesNumber = in.readInt();
+ mZonesColors = in.createIntArray();
+ }
+
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public int getCompressAlgorithm() {
+ return mCompressAlgorithm;
+ }
+
+ public int getSource() {
+ return mSource;
+ }
+
+ public int getColorFormat() {
+ return mColorFormat;
+ }
+
+ public int getHorizontalZonesNumber() {
+ return mHorizontalZonesNumber;
+ }
+
+ public int getVerticalZonesNumber() {
+ return mVerticalZonesNumber;
+ }
+
+ @NonNull
+ public int[] getZonesColors() {
+ return mZonesColors;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mPackageName);
+ dest.writeInt(mCompressAlgorithm);
+ dest.writeInt(mSource);
+ dest.writeInt(mColorFormat);
+ dest.writeInt(mHorizontalZonesNumber);
+ dest.writeInt(mVerticalZonesNumber);
+ dest.writeIntArray(mZonesColors);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Parcelable.Creator<AmbientBacklightMetadata> CREATOR =
+ new Parcelable.Creator<AmbientBacklightMetadata>() {
+ public AmbientBacklightMetadata createFromParcel(Parcel in) {
+ return new AmbientBacklightMetadata(in);
+ }
+
+ public AmbientBacklightMetadata[] newArray(int size) {
+ return new AmbientBacklightMetadata[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "AmbientBacklightMetadata{packageName=" + mPackageName
+ + ", compressAlgorithm=" + mCompressAlgorithm + ", source=" + mSource
+ + ", colorFormat=" + mColorFormat + ", horizontalZonesNumber="
+ + mHorizontalZonesNumber + ", verticalZonesNumber=" + mVerticalZonesNumber
+ + ", zonesColors=" + Arrays.toString(mZonesColors) + "}";
+ }
+}
diff --git a/media/java/android/media/quality/AmbientBacklightSettings.aidl b/media/java/android/media/quality/AmbientBacklightSettings.aidl
new file mode 100644
index 000000000000..e2cdd03194cd
--- /dev/null
+++ b/media/java/android/media/quality/AmbientBacklightSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 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 android.media.quality;
+
+parcelable AmbientBacklightSettings;
diff --git a/media/java/android/media/quality/AmbientBacklightSettings.java b/media/java/android/media/quality/AmbientBacklightSettings.java
new file mode 100644
index 000000000000..391eb225bcab
--- /dev/null
+++ b/media/java/android/media/quality/AmbientBacklightSettings.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2024 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 android.media.quality;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @hide
+ */
+public class AmbientBacklightSettings implements Parcelable {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SOURCE_NONE, SOURCE_AUDIO, SOURCE_VIDEO, SOURCE_AUDIO_VIDEO})
+ public @interface Source {}
+
+ /**
+ * The detection is disabled.
+ */
+ public static final int SOURCE_NONE = 0;
+
+ /**
+ * The detection is enabled for audio.
+ */
+ public static final int SOURCE_AUDIO = 1;
+
+ /**
+ * The detection is enabled for video.
+ */
+ public static final int SOURCE_VIDEO = 2;
+
+ /**
+ * The detection is enabled for audio and video.
+ */
+ public static final int SOURCE_AUDIO_VIDEO = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({COLOR_FORMAT_RGB888})
+ public @interface ColorFormat {}
+
+ /**
+ * The color format is RGB888.
+ */
+ public static final int COLOR_FORMAT_RGB888 = 1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ALGORITHM_NONE, ALGORITHM_RLE})
+ public @interface CompressAlgorithm {}
+
+ /**
+ * The compress algorithm is disabled.
+ */
+ public static final int ALGORITHM_NONE = 0;
+
+ /**
+ * The compress algorithm is RLE.
+ */
+ public static final int ALGORITHM_RLE = 1;
+
+ /**
+ * The source of the ambient backlight.
+ */
+ private final int mSource;
+
+ /**
+ * The maximum framerate for the ambient backlight.
+ */
+ private final int mMaxFps;
+
+ /**
+ * The color format for the ambient backlight.
+ */
+ private final int mColorFormat;
+
+ /**
+ * The number of zones in horizontal direction.
+ */
+ private final int mHorizontalZonesNumber;
+
+ /**
+ * The number of zones in vertical direction.
+ */
+ private final int mVerticalZonesNumber;
+
+ /**
+ * The flag to indicate whether the letterbox is omitted.
+ */
+ private final boolean mIsLetterboxOmitted;
+
+ /**
+ * The color threshold for the ambient backlight.
+ */
+ private final int mThreshold;
+
+ public AmbientBacklightSettings(int source, int maxFps, int colorFormat,
+ int horizontalZonesNumber, int verticalZonesNumber, boolean isLetterboxOmitted,
+ int threshold) {
+ mSource = source;
+ mMaxFps = maxFps;
+ mColorFormat = colorFormat;
+ mHorizontalZonesNumber = horizontalZonesNumber;
+ mVerticalZonesNumber = verticalZonesNumber;
+ mIsLetterboxOmitted = isLetterboxOmitted;
+ mThreshold = threshold;
+ }
+
+ private AmbientBacklightSettings(Parcel in) {
+ mSource = in.readInt();
+ mMaxFps = in.readInt();
+ mColorFormat = in.readInt();
+ mHorizontalZonesNumber = in.readInt();
+ mVerticalZonesNumber = in.readInt();
+ mIsLetterboxOmitted = in.readBoolean();
+ mThreshold = in.readInt();
+ }
+
+ @Source
+ public int getSource() {
+ return mSource;
+ }
+
+ public int getMaxFps() {
+ return mMaxFps;
+ }
+
+ @ColorFormat
+ public int getColorFormat() {
+ return mColorFormat;
+ }
+
+ public int getHorizontalZonesNumber() {
+ return mHorizontalZonesNumber;
+ }
+
+ public int getVerticalZonesNumber() {
+ return mVerticalZonesNumber;
+ }
+
+ public boolean isLetterboxOmitted() {
+ return mIsLetterboxOmitted;
+ }
+
+ public int getThreshold() {
+ return mThreshold;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mSource);
+ dest.writeInt(mMaxFps);
+ dest.writeInt(mColorFormat);
+ dest.writeInt(mHorizontalZonesNumber);
+ dest.writeInt(mVerticalZonesNumber);
+ dest.writeBoolean(mIsLetterboxOmitted);
+ dest.writeInt(mThreshold);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Parcelable.Creator<AmbientBacklightSettings> CREATOR =
+ new Parcelable.Creator<AmbientBacklightSettings>() {
+ public AmbientBacklightSettings createFromParcel(Parcel in) {
+ return new AmbientBacklightSettings(in);
+ }
+
+ public AmbientBacklightSettings[] newArray(int size) {
+ return new AmbientBacklightSettings[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "AmbientBacklightSettings{Source=" + mSource + ", MaxFps=" + mMaxFps
+ + ", ColorFormat=" + mColorFormat + ", HorizontalZonesNumber="
+ + mHorizontalZonesNumber + ", VerticalZonesNumber=" + mVerticalZonesNumber
+ + ", IsLetterboxOmitted=" + mIsLetterboxOmitted + ", Threshold=" + mThreshold + "}";
+ }
+}
diff --git a/media/java/android/media/quality/IAmbientBacklightCallback.aidl b/media/java/android/media/quality/IAmbientBacklightCallback.aidl
new file mode 100644
index 000000000000..159f5b7b5e71
--- /dev/null
+++ b/media/java/android/media/quality/IAmbientBacklightCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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 android.media.quality;
+
+import android.media.quality.AmbientBacklightEvent;
+
+/** @hide */
+oneway interface IAmbientBacklightCallback {
+ void onAmbientBacklightEvent(in AmbientBacklightEvent event);
+}
diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl
index 83f8e795c138..e6c79dd9681f 100644
--- a/media/java/android/media/quality/IMediaQualityManager.aidl
+++ b/media/java/android/media/quality/IMediaQualityManager.aidl
@@ -16,6 +16,8 @@
package android.media.quality;
+import android.media.quality.AmbientBacklightSettings;
+import android.media.quality.IAmbientBacklightCallback;
import android.media.quality.IPictureProfileCallback;
import android.media.quality.ISoundProfileCallback;
import android.media.quality.ParamCapability;
@@ -45,6 +47,7 @@ interface IMediaQualityManager {
void registerPictureProfileCallback(in IPictureProfileCallback cb);
void registerSoundProfileCallback(in ISoundProfileCallback cb);
+ void registerAmbientBacklightCallback(in IAmbientBacklightCallback cb);
List<ParamCapability> getParamCapabilities(in List<String> names);
@@ -55,4 +58,7 @@ interface IMediaQualityManager {
boolean isSuperResolutionEnabled();
void setAutoSoundQualityEnabled(in boolean enabled);
boolean isAutoSoundQualityEnabled();
-} \ No newline at end of file
+
+ void setAmbientBacklightSettings(in AmbientBacklightSettings settings);
+ void setAmbientBacklightEnabled(in boolean enabled);
+}
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 23f3b59faaed..1237d673162c 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -50,6 +50,9 @@ public final class MediaQualityManager {
private final List<PictureProfileCallbackRecord> mPpCallbackRecords = new ArrayList<>();
// @GuardedBy("mLock")
private final List<SoundProfileCallbackRecord> mSpCallbackRecords = new ArrayList<>();
+ // @GuardedBy("mLock")
+ private final List<AmbientBacklightCallbackRecord> mAbCallbackRecords = new ArrayList<>();
+
/**
* @hide
@@ -115,10 +118,22 @@ public final class MediaQualityManager {
}
}
};
+ IAmbientBacklightCallback abCallback = new IAmbientBacklightCallback.Stub() {
+ @Override
+ public void onAmbientBacklightEvent(AmbientBacklightEvent event) {
+ synchronized (mLock) {
+ for (AmbientBacklightCallbackRecord record : mAbCallbackRecords) {
+ record.postAmbientBacklightEvent(event);
+ }
+ }
+ }
+ };
+
try {
if (mService != null) {
mService.registerPictureProfileCallback(ppCallback);
mService.registerSoundProfileCallback(spCallback);
+ mService.registerAmbientBacklightCallback(abCallback);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -455,6 +470,68 @@ public final class MediaQualityManager {
}
}
+ /**
+ * Registers a {@link AmbientBacklightCallback}.
+ * @hide
+ */
+ public void registerAmbientBacklightCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull AmbientBacklightCallback callback) {
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(executor);
+ synchronized (mLock) {
+ mAbCallbackRecords.add(new AmbientBacklightCallbackRecord(callback, executor));
+ }
+ }
+
+ /**
+ * Unregisters the existing {@link AmbientBacklightCallback}.
+ * @hide
+ */
+ public void unregisterAmbientBacklightCallback(
+ @NonNull final AmbientBacklightCallback callback) {
+ Preconditions.checkNotNull(callback);
+ synchronized (mLock) {
+ for (Iterator<AmbientBacklightCallbackRecord> it = mAbCallbackRecords.iterator();
+ it.hasNext(); ) {
+ AmbientBacklightCallbackRecord record = it.next();
+ if (record.getCallback() == callback) {
+ it.remove();
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the ambient backlight settings.
+ *
+ * @param settings The settings to use for the backlight detector.
+ */
+ public void setAmbientBacklightSettings(
+ @NonNull AmbientBacklightSettings settings) {
+ Preconditions.checkNotNull(settings);
+ try {
+ mService.setAmbientBacklightSettings(settings);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enables or disables the ambient backlight detection.
+ *
+ * @param enabled {@code true} to enable, {@code false} to disable.
+ */
+ public void setAmbientBacklightEnabled(boolean enabled) {
+ try {
+ mService.setAmbientBacklightEnabled(enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
private static final class PictureProfileCallbackRecord {
private final PictureProfileCallback mCallback;
private final Executor mExecutor;
@@ -539,6 +616,29 @@ public final class MediaQualityManager {
}
}
+ private static final class AmbientBacklightCallbackRecord {
+ private final AmbientBacklightCallback mCallback;
+ private final Executor mExecutor;
+
+ AmbientBacklightCallbackRecord(AmbientBacklightCallback callback, Executor executor) {
+ mCallback = callback;
+ mExecutor = executor;
+ }
+
+ public AmbientBacklightCallback getCallback() {
+ return mCallback;
+ }
+
+ public void postAmbientBacklightEvent(AmbientBacklightEvent event) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onAmbientBacklightEvent(event);
+ }
+ });
+ }
+ }
+
/**
* Callback used to monitor status of picture profiles.
* @hide
@@ -592,4 +692,16 @@ public final class MediaQualityManager {
public void onError(int errorCode) {
}
}
+
+ /**
+ * Callback used to monitor status of ambient backlight.
+ * @hide
+ */
+ public abstract static class AmbientBacklightCallback {
+ /**
+ * Called when new ambient backlight event is emitted.
+ */
+ public void onAmbientBacklightEvent(AmbientBacklightEvent event) {
+ }
+ }
}
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index e15d41497968..a45ea1d8369d 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -17,6 +17,8 @@
package com.android.server.media.quality;
import android.content.Context;
+import android.media.quality.AmbientBacklightSettings;
+import android.media.quality.IAmbientBacklightCallback;
import android.media.quality.IMediaQualityManager;
import android.media.quality.IPictureProfileCallback;
import android.media.quality.ISoundProfileCallback;
@@ -119,6 +121,17 @@ public class MediaQualityService extends SystemService {
public void registerSoundProfileCallback(final ISoundProfileCallback callback) {
}
+ @Override
+ public void registerAmbientBacklightCallback(IAmbientBacklightCallback callback) {
+ }
+
+ @Override
+ public void setAmbientBacklightSettings(AmbientBacklightSettings settings) {
+ }
+
+ @Override
+ public void setAmbientBacklightEnabled(boolean enabled) {
+ }
@Override
public List<ParamCapability> getParamCapabilities(List<String> names) {