diff options
| author | Vania Desmonda <vaniadesmonda@google.com> | 2022-01-20 08:55:45 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2022-01-20 08:55:45 +0000 |
| commit | 2ad9fe6296242e143bc6ae8890619bec4baf9743 (patch) | |
| tree | f4b534e1f18d7e457f9f25eeb8dd99b342a51775 /core/java/android | |
| parent | 695b7865ed2b1d90a9d7664c05edcbe4791fb317 (diff) | |
| parent | dde365777a3364f5ec32975fcd5af7f0fd681c80 (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.aidl | 23 | ||||
| -rw-r--r-- | core/java/android/app/WallpaperColors.java | 48 | ||||
| -rw-r--r-- | core/java/android/app/WallpaperManager.java | 59 | ||||
| -rw-r--r-- | core/java/android/service/wallpaper/IWallpaperEngine.aidl | 1 | ||||
| -rw-r--r-- | core/java/android/service/wallpaper/WallpaperService.java | 67 |
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; |
