summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorVania Desmonda <vaniadesmonda@google.com>2022-01-20 08:55:45 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2022-01-20 08:55:45 +0000
commit2ad9fe6296242e143bc6ae8890619bec4baf9743 (patch)
treef4b534e1f18d7e457f9f25eeb8dd99b342a51775 /core/java/android
parent695b7865ed2b1d90a9d7664c05edcbe4791fb317 (diff)
parentdde365777a3364f5ec32975fcd5af7f0fd681c80 (diff)
Merge "Add wallpaper dimming SystemAPI and implementation for handling dimming set by multiple applications."
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/IWallpaperManager.aidl23
-rw-r--r--core/java/android/app/WallpaperColors.java48
-rw-r--r--core/java/android/app/WallpaperManager.java59
-rw-r--r--core/java/android/service/wallpaper/IWallpaperEngine.aidl1
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java67
5 files changed, 183 insertions, 15 deletions
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 4f7c6841d6bb..28c273ec50a6 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -204,4 +204,27 @@ interface IWallpaperManager {
* @hide
*/
void notifyGoingToSleep(int x, int y, in Bundle extras);
+
+ /**
+ * Sets the wallpaper dim amount between [0f, 1f] which would be blended with the system default
+ * dimming. 0f doesn't add any additional dimming and 1f makes the wallpaper fully black.
+ *
+ * @hide
+ */
+ oneway void setWallpaperDimAmount(float dimAmount);
+
+ /**
+ * Gets the current additional dim amount set on the wallpaper. 0f means no application has
+ * added any dimming on top of the system default dim amount.
+ *
+ * @hide
+ */
+ float getWallpaperDimAmount();
+
+ /**
+ * Whether the lock screen wallpaper is different from the system wallpaper.
+ *
+ * @hide
+ */
+ boolean lockScreenWallpaperExists();
}
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 7ef0a19ec44c..067a4c3c047e 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,6 +28,7 @@ import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
+import android.util.MathUtils;
import android.util.Size;
import com.android.internal.graphics.ColorUtils;
@@ -44,6 +46,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -173,6 +176,22 @@ public final class WallpaperColors implements Parcelable {
if (bitmap == null) {
throw new IllegalArgumentException("Bitmap can't be null");
}
+ return fromBitmap(bitmap, 0f /* dimAmount */);
+ }
+
+ /**
+ * Constructs {@link WallpaperColors} from a bitmap with dimming applied.
+ * <p>
+ * Main colors will be extracted from the bitmap with dimming taken into account when
+ * calculating dark hints.
+ *
+ * @param bitmap Source where to extract from.
+ * @param dimAmount Wallpaper dim amount
+ * @hide
+ */
+ public static WallpaperColors fromBitmap(@NonNull Bitmap bitmap,
+ @FloatRange (from = 0f, to = 1f) float dimAmount) {
+ Objects.requireNonNull(bitmap, "Bitmap can't be null");
final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
boolean shouldRecycle = false;
@@ -211,7 +230,7 @@ public final class WallpaperColors implements Parcelable {
}
- int hints = calculateDarkHints(bitmap);
+ int hints = calculateDarkHints(bitmap, dimAmount);
if (shouldRecycle) {
bitmap.recycle();
@@ -507,13 +526,15 @@ public final class WallpaperColors implements Parcelable {
* Checks if image is bright and clean enough to support light text.
*
* @param source What to read.
+ * @param dimAmount How much wallpaper dim amount was applied.
* @return Whether image supports dark text or not.
*/
- private static int calculateDarkHints(Bitmap source) {
+ private static int calculateDarkHints(Bitmap source, float dimAmount) {
if (source == null) {
return 0;
}
+ dimAmount = MathUtils.saturate(dimAmount);
int[] pixels = new int[source.getWidth() * source.getHeight()];
double totalLuminance = 0;
final int maxDarkPixels = (int) (pixels.length * MAX_DARK_AREA);
@@ -521,24 +542,37 @@ public final class WallpaperColors implements Parcelable {
source.getPixels(pixels, 0 /* offset */, source.getWidth(), 0 /* x */, 0 /* y */,
source.getWidth(), source.getHeight());
+ // Create a new black layer with dimAmount as the alpha to be accounted for when computing
+ // the luminance.
+ int dimmingLayerAlpha = (int) (255 * dimAmount);
+ int blackTransparent = ColorUtils.setAlphaComponent(Color.BLACK, dimmingLayerAlpha);
+
// This bitmap was already resized to fit the maximum allowed area.
// Let's just loop through the pixels, no sweat!
float[] tmpHsl = new float[3];
for (int i = 0; i < pixels.length; i++) {
- ColorUtils.colorToHSL(pixels[i], tmpHsl);
- final float luminance = tmpHsl[2];
- final int alpha = Color.alpha(pixels[i]);
+ int pixelColor = pixels[i];
+ ColorUtils.colorToHSL(pixelColor, tmpHsl);
+ final int alpha = Color.alpha(pixelColor);
+
+ // Apply composite colors where the foreground is a black layer with an alpha value of
+ // the dim amount and the background is the wallpaper pixel color.
+ int compositeColors = ColorUtils.compositeColors(blackTransparent, pixelColor);
+
+ // Calculate the adjusted luminance of the dimmed wallpaper pixel color.
+ double adjustedLuminance = ColorUtils.calculateLuminance(compositeColors);
+
// Make sure we don't have a dark pixel mass that will
// make text illegible.
final boolean satisfiesTextContrast = ContrastColorUtil
- .calculateContrast(pixels[i], Color.BLACK) > DARK_PIXEL_CONTRAST;
+ .calculateContrast(pixelColor, Color.BLACK) > DARK_PIXEL_CONTRAST;
if (!satisfiesTextContrast && alpha != 0) {
darkPixels++;
if (DEBUG_DARK_PIXELS) {
pixels[i] = Color.RED;
}
}
- totalLuminance += luminance;
+ totalLuminance += adjustedLuminance;
}
int hints = 0;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 61bf9b308875..0a18588e0131 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -71,6 +72,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.MathUtils;
import android.util.Pair;
import android.view.Display;
import android.view.WindowManagerGlobal;
@@ -1994,6 +1996,63 @@ public class WallpaperManager {
}
/**
+ * Sets the wallpaper dim amount between [0f, 1f] which would be blended with the system default
+ * dimming. 0f doesn't add any additional dimming and 1f makes the wallpaper fully black.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT)
+ public void setWallpaperDimAmount(@FloatRange (from = 0f, to = 1f) float dimAmount) {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ throw new RuntimeException(new DeadSystemException());
+ }
+ try {
+ sGlobals.mService.setWallpaperDimAmount(MathUtils.saturate(dimAmount));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the current additional dim amount set on the wallpaper. 0f means no application has
+ * added any dimming on top of the system default dim amount.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT)
+ public float getWallpaperDimAmount() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ throw new RuntimeException(new DeadSystemException());
+ }
+ try {
+ return sGlobals.mService.getWallpaperDimAmount();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Whether the lock screen wallpaper is different from the system wallpaper.
+ *
+ * @hide
+ */
+ public boolean lockScreenWallpaperExists() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ throw new RuntimeException(new DeadSystemException());
+ }
+ try {
+ return sGlobals.mService.lockScreenWallpaperExists();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Set the live wallpaper.
*
* This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT
diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
index 81af6a220444..93d4def2180e 100644
--- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
@@ -46,4 +46,5 @@ interface IWallpaperEngine {
oneway void removeLocalColorsAreas(in List<RectF> regions);
oneway void addLocalColorsAreas(in List<RectF> regions);
SurfaceControl mirrorSurfaceControl();
+ oneway void applyDimming(float dimAmount);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 73ffd66486d2..bff75a62b590 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -26,6 +26,7 @@ import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import android.animation.ValueAnimator;
import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -159,6 +160,7 @@ public abstract class WallpaperService extends Service {
private static final int MSG_ZOOM = 10100;
private static final int MSG_SCALE_PREVIEW = 10110;
private static final int MSG_REPORT_SHOWN = 10150;
+ private static final int MSG_UPDATE_DIMMING = 10200;
private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY,
Float.NEGATIVE_INFINITY);
@@ -167,6 +169,8 @@ public abstract class WallpaperService extends Service {
private static final boolean ENABLE_WALLPAPER_DIMMING =
SystemProperties.getBoolean("persist.debug.enable_wallpaper_dimming", true);
+ private static final long DIMMING_ANIMATION_DURATION_MS = 300L;
+
private final ArrayList<Engine> mActiveEngines
= new ArrayList<Engine>();
@@ -221,6 +225,9 @@ public abstract class WallpaperService extends Service {
boolean mOffsetsChanged;
boolean mFixedSizeAllowed;
boolean mShouldDim;
+ // Whether the wallpaper should be dimmed by default (when no additional dimming is applied)
+ // based on its color hints
+ boolean mShouldDimByDefault;
int mWidth;
int mHeight;
int mFormat;
@@ -272,6 +279,8 @@ public abstract class WallpaperService extends Service {
private Context mDisplayContext;
private int mDisplayState;
private float mWallpaperDimAmount = 0.05f;
+ private float mPreviousWallpaperDimAmount = mWallpaperDimAmount;
+ private float mDefaultDimAmount = mWallpaperDimAmount;
SurfaceControl mSurfaceControl = new SurfaceControl();
SurfaceControl mBbqSurfaceControl;
@@ -861,15 +870,34 @@ public abstract class WallpaperService extends Service {
return;
}
int colorHints = colors.getColorHints();
- boolean shouldDim = ((colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0
+ mShouldDimByDefault = ((colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0
&& (colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) == 0);
- if (shouldDim != mShouldDim) {
- mShouldDim = shouldDim;
+
+ // If default dimming value changes and no additional dimming is applied
+ if (mShouldDimByDefault != mShouldDim && mWallpaperDimAmount == 0f) {
+ mShouldDim = mShouldDimByDefault;
updateSurfaceDimming();
updateSurface(false, false, true);
}
}
+ /**
+ * Update the dim amount of the wallpaper by updating the surface.
+ *
+ * @param dimAmount Float amount between [0.0, 1.0] to dim the wallpaper.
+ */
+ private void updateWallpaperDimming(float dimAmount) {
+ mPreviousWallpaperDimAmount = mWallpaperDimAmount;
+
+ // Custom dim amount cannot be less than the default dim amount.
+ mWallpaperDimAmount = Math.max(mDefaultDimAmount, dimAmount);
+ // If dim amount is 0f (additional dimming is removed), then the wallpaper should dim
+ // based on its default wallpaper color hints.
+ mShouldDim = dimAmount != 0f || mShouldDimByDefault;
+ updateSurfaceDimming();
+ updateSurface(false, false, true);
+ }
+
private void updateSurfaceDimming() {
if (!ENABLE_WALLPAPER_DIMMING || mBbqSurfaceControl == null) {
return;
@@ -878,9 +906,21 @@ public abstract class WallpaperService extends Service {
// preview mode.
if (!isPreview() && mShouldDim) {
Log.v(TAG, "Setting wallpaper dimming: " + mWallpaperDimAmount);
- new SurfaceControl.Transaction()
- .setAlpha(mBbqSurfaceControl, 1 - mWallpaperDimAmount)
- .apply();
+ SurfaceControl.Transaction surfaceControl = new SurfaceControl.Transaction();
+
+ // Animate dimming to gradually change the wallpaper alpha from the previous
+ // dim amount to the new amount only if the dim amount changed.
+ ValueAnimator animator = ValueAnimator.ofFloat(
+ mPreviousWallpaperDimAmount, mWallpaperDimAmount);
+ animator.setDuration(mPreviousWallpaperDimAmount == mWallpaperDimAmount
+ ? 0 : DIMMING_ANIMATION_DURATION_MS);
+ animator.addUpdateListener((ValueAnimator va) -> {
+ final float dimValue = (float) va.getAnimatedValue();
+ surfaceControl
+ .setAlpha(mBbqSurfaceControl, 1 - dimValue)
+ .apply();
+ });
+ animator.start();
} else {
Log.v(TAG, "Setting wallpaper dimming: " + 0);
new SurfaceControl.Transaction()
@@ -1332,8 +1372,10 @@ public abstract class WallpaperService extends Service {
// Use window context of TYPE_WALLPAPER so client can access UI resources correctly.
mDisplayContext = createDisplayContext(mDisplay)
.createWindowContext(TYPE_WALLPAPER, null /* options */);
- mWallpaperDimAmount = mDisplayContext.getResources().getFloat(
+ mDefaultDimAmount = mDisplayContext.getResources().getFloat(
com.android.internal.R.dimen.config_wallpaperDimAmount);
+ mWallpaperDimAmount = mDefaultDimAmount;
+ mPreviousWallpaperDimAmount = mWallpaperDimAmount;
mDisplayState = mDisplay.getState();
if (DEBUG) Log.v(TAG, "onCreate(): " + this);
@@ -1647,7 +1689,7 @@ public abstract class WallpaperService extends Service {
Log.e(TAG, "Error creating page local color bitmap", e);
continue;
}
- WallpaperColors color = WallpaperColors.fromBitmap(target);
+ WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount);
target.recycle();
WallpaperColors currentColor = page.getColors(area);
@@ -2175,6 +2217,12 @@ public abstract class WallpaperService extends Service {
mDetached.set(true);
}
+ public void applyDimming(float dimAmount) throws RemoteException {
+ Message msg = mCaller.obtainMessageI(MSG_UPDATE_DIMMING,
+ Float.floatToIntBits(dimAmount));
+ mCaller.sendMessage(msg);
+ }
+
public void scalePreview(Rect position) {
Message msg = mCaller.obtainMessageO(MSG_SCALE_PREVIEW, position);
mCaller.sendMessage(msg);
@@ -2245,6 +2293,9 @@ public abstract class WallpaperService extends Service {
case MSG_ZOOM:
mEngine.setZoom(Float.intBitsToFloat(message.arg1));
break;
+ case MSG_UPDATE_DIMMING:
+ mEngine.updateWallpaperDimming(Float.intBitsToFloat(message.arg1));
+ break;
case MSG_SCALE_PREVIEW:
mEngine.scalePreview((Rect) message.obj);
break;