Loading core/java/android/service/wallpaper/WallpaperService.java +105 −61 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ import android.hardware.display.DisplayManager.DisplayListener; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; Loading Loading @@ -180,6 +181,9 @@ public abstract class WallpaperService extends Service { private final ArrayList<Engine> mActiveEngines = new ArrayList<Engine>(); private Handler mBackgroundHandler; private HandlerThread mBackgroundThread; static final class WallpaperCommand { String action; int x; Loading @@ -198,14 +202,6 @@ public abstract class WallpaperService extends Service { */ public class Engine { IWallpaperEngineWrapper mIWallpaperEngine; final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); // 2D matrix [x][y] to represent a page of a portion of a window EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; Bitmap mLastScreenshot; int mLastWindowPage = -1; private boolean mResetWindowPages; // Copies from mIWallpaperEngine. HandlerCaller mCaller; Loading Loading @@ -267,11 +263,27 @@ public abstract class WallpaperService extends Service { final Object mLock = new Object(); boolean mOffsetMessageEnqueued; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) float mPendingXOffset; float mPendingYOffset; float mPendingXOffsetStep; float mPendingYOffsetStep; /** * local color extraction related fields * to be used by the background thread only (except the atomic boolean) */ final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); private long mLastProcessLocalColorsTimestamp; private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); private int mPixelCopyCount = 0; // 2D matrix [x][y] to represent a page of a portion of a window EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; Bitmap mLastScreenshot; private boolean mResetWindowPages; boolean mPendingSync; MotionEvent mPendingMove; boolean mIsInAmbientMode; Loading @@ -280,12 +292,8 @@ public abstract class WallpaperService extends Service { private long mLastColorInvalidation; private final Runnable mNotifyColorsChanged = this::notifyColorsChanged; // used to throttle processLocalColors private long mLastProcessLocalColorsTimestamp; private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); private final Supplier<Long> mClockFunction; private final Handler mHandler; private Display mDisplay; private Context mDisplayContext; private int mDisplayState; Loading Loading @@ -825,7 +833,7 @@ public abstract class WallpaperService extends Service { + "was not established."); } mResetWindowPages = true; processLocalColors(mPendingXOffset, mPendingXOffsetStep); processLocalColors(); } catch (RemoteException e) { Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e); } Loading Loading @@ -1364,7 +1372,7 @@ public abstract class WallpaperService extends Service { resetWindowPages(); mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE); processLocalColors(mPendingXOffset, mPendingXOffsetStep); processLocalColors(); } reposition(); reportEngineShown(shouldWaitForEngineShown()); Loading Loading @@ -1509,7 +1517,7 @@ public abstract class WallpaperService extends Service { if (!mDestroyed) { mVisible = visible; reportVisibility(); if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep); if (mReportedVisible) processLocalColors(); } else { AnimationHandler.requestAnimatorsEnabled(visible, this); } Loading Loading @@ -1593,31 +1601,41 @@ public abstract class WallpaperService extends Service { } // setup local color extraction data processLocalColors(xOffset, xOffsetStep); processLocalColors(); } /** * Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of * {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls. */ private void processLocalColors(float xOffset, float xOffsetStep) { private void processLocalColors() { if (mProcessLocalColorsPending.compareAndSet(false, true)) { final long now = mClockFunction.get(); final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp; final long timeToWait = Math.max(0, PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess); mHandler.postDelayed(() -> { mBackgroundHandler.postDelayed(() -> { mLastProcessLocalColorsTimestamp = now + timeToWait; mProcessLocalColorsPending.set(false); processLocalColorsInternal(xOffset, xOffsetStep); processLocalColorsInternal(); }, timeToWait); } } private void processLocalColorsInternal(float xOffset, float xOffsetStep) { private void processLocalColorsInternal() { // implemented by the wallpaper if (supportsLocalColorExtraction()) return; assertBackgroundThread(); float xOffset; float xOffsetStep; float wallpaperDimAmount; synchronized (mLock) { xOffset = mPendingXOffset; xOffsetStep = mPendingXOffsetStep; wallpaperDimAmount = mWallpaperDimAmount; } if (DEBUG) { Log.d(TAG, "processLocalColors " + xOffset + " of step " + xOffsetStep); Loading Loading @@ -1680,7 +1698,7 @@ public abstract class WallpaperService extends Service { xPage = mWindowPages.length - 1; } current = mWindowPages[xPage]; updatePage(current, xPage, xPages, finalXOffsetStep); updatePage(current, xPage, xPages, wallpaperDimAmount); Trace.endSection(); } Loading @@ -1700,16 +1718,23 @@ public abstract class WallpaperService extends Service { } } /** * Must be called with the surface lock held. * Must not be called if the surface is not valid. * Will unlock the surface when done using it. */ void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages, float xOffsetStep) { float wallpaperDimAmount) { assertBackgroundThread(); // in case the clock is zero, we start with negative time long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION; long lapsed = current - currentPage.getLastUpdateTime(); // Always update the page when the last update time is <= 0 // This is important especially when the device first boots if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) { return; } if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return; Surface surface = mSurfaceHolder.getSurface(); if (!surface.isValid()) return; boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y; Loading @@ -1725,9 +1750,12 @@ public abstract class WallpaperService extends Service { Bitmap screenShot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Bitmap finalScreenShot = screenShot; Trace.beginSection("WallpaperService#pixelCopy"); final String pixelCopySectionName = "WallpaperService#pixelCopy"; final int pixelCopyCount = mPixelCopyCount++; Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount); try { PixelCopy.request(surface, screenShot, (res) -> { Trace.endSection(); Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount); if (DEBUG) Log.d(TAG, "result of pixel copy is " + res); if (res != PixelCopy.SUCCESS) { Bitmap lastBitmap = currentPage.getBitmap(); Loading @@ -1736,22 +1764,28 @@ public abstract class WallpaperService extends Service { Bitmap lastScreenshot = mLastScreenshot; if (lastScreenshot != null && !lastScreenshot.isRecycled() && !Objects.equals(lastBitmap, lastScreenshot)) { updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount); } } else { mLastScreenshot = finalScreenShot; // going to hold this lock for a while currentPage.setBitmap(finalScreenShot); currentPage.setLastUpdateTime(current); updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount); } }, mBackgroundHandler); } catch (IllegalArgumentException e) { // this can potentially happen if the surface is invalidated right between the // surface.isValid() check and the PixelCopy operation. // in this case, stop: we'll compute colors on the next processLocalColors call. Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy"); } }, mHandler); } // locked by the passed page private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages, float xOffsetStep) { private void updatePageColors( EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) { if (page.getBitmap() == null) return; assertBackgroundThread(); Trace.beginSection("WallpaperService#updatePageColors"); if (DEBUG) { Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas " Loading @@ -1773,7 +1807,7 @@ public abstract class WallpaperService extends Service { Log.e(TAG, "Error creating page local color bitmap", e); continue; } WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount); WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount); target.recycle(); WallpaperColors currentColor = page.getColors(area); Loading @@ -1790,17 +1824,26 @@ public abstract class WallpaperService extends Service { + " local color callback for area" + area + " for page " + pageIndx + " of " + numPages); } mHandler.post(() -> { try { mConnection.onLocalWallpaperColorsChanged(area, color, mDisplayContext.getDisplayId()); } catch (RemoteException e) { Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); } }); } } Trace.endSection(); } private void assertBackgroundThread() { if (!mBackgroundHandler.getLooper().isCurrentThread()) { throw new IllegalStateException( "ProcessLocalColors should be called from the background thread"); } } private RectF generateSubRect(RectF in, int pageInx, int numPages) { float minLeft = (float) (pageInx) / (float) (numPages); float maxRight = (float) (pageInx + 1) / (float) (numPages); Loading @@ -1825,7 +1868,6 @@ public abstract class WallpaperService extends Service { if (supportsLocalColorExtraction()) return; if (!mResetWindowPages) return; mResetWindowPages = false; mLastWindowPage = -1; for (int i = 0; i < mWindowPages.length; i++) { mWindowPages[i].setLastUpdateTime(0L); } Loading @@ -1851,12 +1893,10 @@ public abstract class WallpaperService extends Service { if (DEBUG) { Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions); } mHandler.post(() -> { mBackgroundHandler.post(() -> { mLocalColorsToAdd.addAll(regions); processLocalColors(mPendingXOffset, mPendingYOffset); processLocalColors(); }); } /** Loading @@ -1866,7 +1906,7 @@ public abstract class WallpaperService extends Service { */ public void removeLocalColorsAreas(@NonNull List<RectF> regions) { if (supportsLocalColorExtraction()) return; mHandler.post(() -> { mBackgroundHandler.post(() -> { float step = mPendingXOffsetStep; mLocalColorsToAdd.removeAll(regions); mLocalColorAreas.removeAll(regions); Loading Loading @@ -2497,6 +2537,9 @@ public abstract class WallpaperService extends Service { @Override public void onCreate() { Trace.beginSection("WPMS.onCreate"); mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); super.onCreate(); Trace.endSection(); } Loading @@ -2509,6 +2552,7 @@ public abstract class WallpaperService extends Service { mActiveEngines.get(i).detach(); } mActiveEngines.clear(); mBackgroundThread.quitSafely(); Trace.endSection(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +14 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View handle = caption.findViewById(R.id.caption_handle); handle.setOnTouchListener(mOnCaptionTouchListener); handle.setOnClickListener(mOnCaptionButtonClickListener); if (DesktopModeStatus.isProto1Enabled()) { final View back = caption.findViewById(R.id.back_button); back.setOnClickListener(mOnCaptionButtonClickListener); final View close = caption.findViewById(R.id.close_window); close.setOnClickListener(mOnCaptionButtonClickListener); } updateButtonVisibility(); } Loading Loading @@ -319,6 +325,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View handle = caption.findViewById(R.id.caption_handle); final Drawable handleBackground = handle.getBackground(); handleBackground.setTintList(buttonTintColor); if (DesktopModeStatus.isProto1Enabled()) { final View back = caption.findViewById(R.id.back_button); final Drawable backBackground = back.getBackground(); backBackground.setTintList(buttonTintColor); final View close = caption.findViewById(R.id.close_window); final Drawable closeBackground = close.getBackground(); closeBackground.setTintList(buttonTintColor); } } private void closeDragResizeListener() { Loading packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt +1 −2 Original line number Diff line number Diff line Loading @@ -35,8 +35,7 @@ interface LaunchableView { * * Note that calls to [View.setTransitionVisibility] shouldn't be blocked. * * @param block whether we should block/postpone all calls to `setVisibility` and * `setTransitionVisibility`. * @param block whether we should block/postpone all calls to `setVisibility`. */ fun setShouldBlockVisibilityChanges(block: Boolean) } Loading packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt +1 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ class RippleAnimation(private val config: RippleAnimationConfig) { private fun applyConfigToShader() { with(rippleShader) { setCenter(config.centerX, config.centerY) setMaxSize(config.maxWidth, config.maxHeight) rippleSize.setMaxSize(config.maxWidth, config.maxHeight) pixelDensity = config.pixelDensity color = ColorUtils.setAlphaComponent(config.color, config.opacity) sparkleStrength = config.sparkleStrength Loading packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt +124 −21 Original line number Diff line number Diff line Loading @@ -15,9 +15,10 @@ */ package com.android.systemui.surfaceeffects.ripple import android.graphics.PointF import android.graphics.RuntimeShader import android.util.Log import android.util.MathUtils import androidx.annotation.VisibleForTesting import com.android.systemui.animation.Interpolators import com.android.systemui.surfaceeffects.shaderutil.SdfShaderLibrary import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary Loading @@ -44,6 +45,8 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : } // language=AGSL companion object { private val TAG = RippleShader::class.simpleName // Default fade in/ out values. The value range is [0,1]. const val DEFAULT_FADE_IN_START = 0f const val DEFAULT_FADE_OUT_END = 1f Loading Loading @@ -99,7 +102,7 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : vec4 main(vec2 p) { float sparkleRing = soften(roundedBoxRing(p-in_center, in_size, in_cornerRadius, in_thickness), in_blur); float inside = soften(sdRoundedBox(p-in_center, in_size * 1.2, in_cornerRadius), float inside = soften(sdRoundedBox(p-in_center, in_size * 1.25, in_cornerRadius), in_blur); float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175) * (1.-sparkleRing) * in_fadeSparkle; Loading Loading @@ -184,12 +187,17 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : setFloatUniform("in_center", x, y) } /** Max width of the ripple. */ private var maxSize: PointF = PointF() fun setMaxSize(width: Float, height: Float) { maxSize.x = width maxSize.y = height } /** * Blur multipliers for the ripple. * * <p>It interpolates from [blurStart] to [blurEnd] based on the [progress]. Increase number to * add more blur. */ var blurStart: Float = 1.25f var blurEnd: Float = 0.5f /** Size of the ripple. */ val rippleSize = RippleSize() /** * Linear progress of the ripple. Float value between [0, 1]. Loading @@ -209,15 +217,19 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : /** Progress with Standard easing curve applied. */ private var progress: Float = 0.0f set(value) { currentWidth = maxSize.x * value currentHeight = maxSize.y * value setFloatUniform("in_size", currentWidth, currentHeight) field = value setFloatUniform("in_thickness", maxSize.y * value * 0.5f) // radius should not exceed width and height values. setFloatUniform("in_cornerRadius", Math.min(maxSize.x, maxSize.y) * value) rippleSize.update(value) setFloatUniform("in_blur", MathUtils.lerp(1.25f, 0.5f, value)) setFloatUniform("in_size", rippleSize.currentWidth, rippleSize.currentHeight) setFloatUniform("in_thickness", rippleSize.currentHeight * 0.5f) // Corner radius is always max of the min between the current width and height. setFloatUniform( "in_cornerRadius", Math.min(rippleSize.currentWidth, rippleSize.currentHeight) ) setFloatUniform("in_blur", MathUtils.lerp(blurStart, blurEnd, value)) } /** Play time since the start of the effect. */ Loading Loading @@ -264,12 +276,6 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : setFloatUniform("in_pixelDensity", value) } var currentWidth: Float = 0f private set var currentHeight: Float = 0f private set /** Parameters that are used to fade in/ out of the sparkle ring. */ val sparkleRingFadeParams = FadeParams( Loading Loading @@ -342,4 +348,101 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : /** The endpoint of the fade out, given that the animation goes from 0 to 1. */ var fadeOutEnd: Float = DEFAULT_FADE_OUT_END, ) /** * Desired size of the ripple at a point t in [progress]. * * <p>Note that [progress] is curved and normalized. Below is an example usage: * SizeAtProgress(t= 0f, width= 0f, height= 0f), SizeAtProgress(t= 0.2f, width= 500f, height= * 700f), SizeAtProgress(t= 1f, width= 100f, height= 300f) * * <p>For simple ripple effects, you will want to use [setMaxSize] as it is translated into: * SizeAtProgress(t= 0f, width= 0f, height= 0f), SizeAtProgress(t= 1f, width= maxWidth, height= * maxHeight) */ data class SizeAtProgress( /** Time t in [0,1] progress range. */ var t: Float, /** Target width size of the ripple at time [t]. */ var width: Float, /** Target height size of the ripple at time [t]. */ var height: Float ) /** Updates and stores the ripple size. */ inner class RippleSize { @VisibleForTesting var sizes = mutableListOf<SizeAtProgress>() @VisibleForTesting var currentSizeIndex = 0 @VisibleForTesting val initialSize = SizeAtProgress(0f, 0f, 0f) var currentWidth: Float = 0f private set var currentHeight: Float = 0f private set /** * Sets the max size of the ripple. * * <p>Use this if the ripple shape simply changes linearly. */ fun setMaxSize(width: Float, height: Float) { setSizeAtProgresses(initialSize, SizeAtProgress(1f, width, height)) } /** * Sets the list of [sizes]. * * <p>Note that setting this clears the existing sizes. */ fun setSizeAtProgresses(vararg sizes: SizeAtProgress) { // Reset everything. this.sizes.clear() currentSizeIndex = 0 this.sizes.addAll(sizes) this.sizes.sortBy { it.t } } /** * Updates the current ripple size based on the progress. * * <p>Should be called when progress updates. */ fun update(progress: Float) { val targetIndex = updateTargetIndex(progress) val prevIndex = Math.max(targetIndex - 1, 0) val targetSize = sizes[targetIndex] val prevSize = sizes[prevIndex] val subProgress = subProgress(prevSize.t, targetSize.t, progress) currentWidth = targetSize.width * subProgress + prevSize.width currentHeight = targetSize.height * subProgress + prevSize.height } private fun updateTargetIndex(progress: Float): Int { if (sizes.isEmpty()) { // It could be empty on init. if (progress > 0f) { Log.e( TAG, "Did you forget to set the ripple size? Use [setMaxSize] or " + "[setSizeAtProgresses] before playing the animation." ) } // If there's no size is set, we set everything to 0. setSizeAtProgresses(initialSize) } var candidate = sizes[currentSizeIndex] while (progress > candidate.t) { currentSizeIndex = Math.min(currentSizeIndex + 1, sizes.size - 1) candidate = sizes[currentSizeIndex] } return currentSizeIndex } } } Loading
core/java/android/service/wallpaper/WallpaperService.java +105 −61 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ import android.hardware.display.DisplayManager.DisplayListener; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; Loading Loading @@ -180,6 +181,9 @@ public abstract class WallpaperService extends Service { private final ArrayList<Engine> mActiveEngines = new ArrayList<Engine>(); private Handler mBackgroundHandler; private HandlerThread mBackgroundThread; static final class WallpaperCommand { String action; int x; Loading @@ -198,14 +202,6 @@ public abstract class WallpaperService extends Service { */ public class Engine { IWallpaperEngineWrapper mIWallpaperEngine; final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); // 2D matrix [x][y] to represent a page of a portion of a window EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; Bitmap mLastScreenshot; int mLastWindowPage = -1; private boolean mResetWindowPages; // Copies from mIWallpaperEngine. HandlerCaller mCaller; Loading Loading @@ -267,11 +263,27 @@ public abstract class WallpaperService extends Service { final Object mLock = new Object(); boolean mOffsetMessageEnqueued; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) float mPendingXOffset; float mPendingYOffset; float mPendingXOffsetStep; float mPendingYOffsetStep; /** * local color extraction related fields * to be used by the background thread only (except the atomic boolean) */ final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); private long mLastProcessLocalColorsTimestamp; private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); private int mPixelCopyCount = 0; // 2D matrix [x][y] to represent a page of a portion of a window EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; Bitmap mLastScreenshot; private boolean mResetWindowPages; boolean mPendingSync; MotionEvent mPendingMove; boolean mIsInAmbientMode; Loading @@ -280,12 +292,8 @@ public abstract class WallpaperService extends Service { private long mLastColorInvalidation; private final Runnable mNotifyColorsChanged = this::notifyColorsChanged; // used to throttle processLocalColors private long mLastProcessLocalColorsTimestamp; private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); private final Supplier<Long> mClockFunction; private final Handler mHandler; private Display mDisplay; private Context mDisplayContext; private int mDisplayState; Loading Loading @@ -825,7 +833,7 @@ public abstract class WallpaperService extends Service { + "was not established."); } mResetWindowPages = true; processLocalColors(mPendingXOffset, mPendingXOffsetStep); processLocalColors(); } catch (RemoteException e) { Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e); } Loading Loading @@ -1364,7 +1372,7 @@ public abstract class WallpaperService extends Service { resetWindowPages(); mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE); processLocalColors(mPendingXOffset, mPendingXOffsetStep); processLocalColors(); } reposition(); reportEngineShown(shouldWaitForEngineShown()); Loading Loading @@ -1509,7 +1517,7 @@ public abstract class WallpaperService extends Service { if (!mDestroyed) { mVisible = visible; reportVisibility(); if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep); if (mReportedVisible) processLocalColors(); } else { AnimationHandler.requestAnimatorsEnabled(visible, this); } Loading Loading @@ -1593,31 +1601,41 @@ public abstract class WallpaperService extends Service { } // setup local color extraction data processLocalColors(xOffset, xOffsetStep); processLocalColors(); } /** * Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of * {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls. */ private void processLocalColors(float xOffset, float xOffsetStep) { private void processLocalColors() { if (mProcessLocalColorsPending.compareAndSet(false, true)) { final long now = mClockFunction.get(); final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp; final long timeToWait = Math.max(0, PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess); mHandler.postDelayed(() -> { mBackgroundHandler.postDelayed(() -> { mLastProcessLocalColorsTimestamp = now + timeToWait; mProcessLocalColorsPending.set(false); processLocalColorsInternal(xOffset, xOffsetStep); processLocalColorsInternal(); }, timeToWait); } } private void processLocalColorsInternal(float xOffset, float xOffsetStep) { private void processLocalColorsInternal() { // implemented by the wallpaper if (supportsLocalColorExtraction()) return; assertBackgroundThread(); float xOffset; float xOffsetStep; float wallpaperDimAmount; synchronized (mLock) { xOffset = mPendingXOffset; xOffsetStep = mPendingXOffsetStep; wallpaperDimAmount = mWallpaperDimAmount; } if (DEBUG) { Log.d(TAG, "processLocalColors " + xOffset + " of step " + xOffsetStep); Loading Loading @@ -1680,7 +1698,7 @@ public abstract class WallpaperService extends Service { xPage = mWindowPages.length - 1; } current = mWindowPages[xPage]; updatePage(current, xPage, xPages, finalXOffsetStep); updatePage(current, xPage, xPages, wallpaperDimAmount); Trace.endSection(); } Loading @@ -1700,16 +1718,23 @@ public abstract class WallpaperService extends Service { } } /** * Must be called with the surface lock held. * Must not be called if the surface is not valid. * Will unlock the surface when done using it. */ void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages, float xOffsetStep) { float wallpaperDimAmount) { assertBackgroundThread(); // in case the clock is zero, we start with negative time long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION; long lapsed = current - currentPage.getLastUpdateTime(); // Always update the page when the last update time is <= 0 // This is important especially when the device first boots if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) { return; } if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return; Surface surface = mSurfaceHolder.getSurface(); if (!surface.isValid()) return; boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y; Loading @@ -1725,9 +1750,12 @@ public abstract class WallpaperService extends Service { Bitmap screenShot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Bitmap finalScreenShot = screenShot; Trace.beginSection("WallpaperService#pixelCopy"); final String pixelCopySectionName = "WallpaperService#pixelCopy"; final int pixelCopyCount = mPixelCopyCount++; Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount); try { PixelCopy.request(surface, screenShot, (res) -> { Trace.endSection(); Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount); if (DEBUG) Log.d(TAG, "result of pixel copy is " + res); if (res != PixelCopy.SUCCESS) { Bitmap lastBitmap = currentPage.getBitmap(); Loading @@ -1736,22 +1764,28 @@ public abstract class WallpaperService extends Service { Bitmap lastScreenshot = mLastScreenshot; if (lastScreenshot != null && !lastScreenshot.isRecycled() && !Objects.equals(lastBitmap, lastScreenshot)) { updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount); } } else { mLastScreenshot = finalScreenShot; // going to hold this lock for a while currentPage.setBitmap(finalScreenShot); currentPage.setLastUpdateTime(current); updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount); } }, mBackgroundHandler); } catch (IllegalArgumentException e) { // this can potentially happen if the surface is invalidated right between the // surface.isValid() check and the PixelCopy operation. // in this case, stop: we'll compute colors on the next processLocalColors call. Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy"); } }, mHandler); } // locked by the passed page private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages, float xOffsetStep) { private void updatePageColors( EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) { if (page.getBitmap() == null) return; assertBackgroundThread(); Trace.beginSection("WallpaperService#updatePageColors"); if (DEBUG) { Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas " Loading @@ -1773,7 +1807,7 @@ public abstract class WallpaperService extends Service { Log.e(TAG, "Error creating page local color bitmap", e); continue; } WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount); WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount); target.recycle(); WallpaperColors currentColor = page.getColors(area); Loading @@ -1790,17 +1824,26 @@ public abstract class WallpaperService extends Service { + " local color callback for area" + area + " for page " + pageIndx + " of " + numPages); } mHandler.post(() -> { try { mConnection.onLocalWallpaperColorsChanged(area, color, mDisplayContext.getDisplayId()); } catch (RemoteException e) { Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); } }); } } Trace.endSection(); } private void assertBackgroundThread() { if (!mBackgroundHandler.getLooper().isCurrentThread()) { throw new IllegalStateException( "ProcessLocalColors should be called from the background thread"); } } private RectF generateSubRect(RectF in, int pageInx, int numPages) { float minLeft = (float) (pageInx) / (float) (numPages); float maxRight = (float) (pageInx + 1) / (float) (numPages); Loading @@ -1825,7 +1868,6 @@ public abstract class WallpaperService extends Service { if (supportsLocalColorExtraction()) return; if (!mResetWindowPages) return; mResetWindowPages = false; mLastWindowPage = -1; for (int i = 0; i < mWindowPages.length; i++) { mWindowPages[i].setLastUpdateTime(0L); } Loading @@ -1851,12 +1893,10 @@ public abstract class WallpaperService extends Service { if (DEBUG) { Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions); } mHandler.post(() -> { mBackgroundHandler.post(() -> { mLocalColorsToAdd.addAll(regions); processLocalColors(mPendingXOffset, mPendingYOffset); processLocalColors(); }); } /** Loading @@ -1866,7 +1906,7 @@ public abstract class WallpaperService extends Service { */ public void removeLocalColorsAreas(@NonNull List<RectF> regions) { if (supportsLocalColorExtraction()) return; mHandler.post(() -> { mBackgroundHandler.post(() -> { float step = mPendingXOffsetStep; mLocalColorsToAdd.removeAll(regions); mLocalColorAreas.removeAll(regions); Loading Loading @@ -2497,6 +2537,9 @@ public abstract class WallpaperService extends Service { @Override public void onCreate() { Trace.beginSection("WPMS.onCreate"); mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); super.onCreate(); Trace.endSection(); } Loading @@ -2509,6 +2552,7 @@ public abstract class WallpaperService extends Service { mActiveEngines.get(i).detach(); } mActiveEngines.clear(); mBackgroundThread.quitSafely(); Trace.endSection(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +14 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View handle = caption.findViewById(R.id.caption_handle); handle.setOnTouchListener(mOnCaptionTouchListener); handle.setOnClickListener(mOnCaptionButtonClickListener); if (DesktopModeStatus.isProto1Enabled()) { final View back = caption.findViewById(R.id.back_button); back.setOnClickListener(mOnCaptionButtonClickListener); final View close = caption.findViewById(R.id.close_window); close.setOnClickListener(mOnCaptionButtonClickListener); } updateButtonVisibility(); } Loading Loading @@ -319,6 +325,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View handle = caption.findViewById(R.id.caption_handle); final Drawable handleBackground = handle.getBackground(); handleBackground.setTintList(buttonTintColor); if (DesktopModeStatus.isProto1Enabled()) { final View back = caption.findViewById(R.id.back_button); final Drawable backBackground = back.getBackground(); backBackground.setTintList(buttonTintColor); final View close = caption.findViewById(R.id.close_window); final Drawable closeBackground = close.getBackground(); closeBackground.setTintList(buttonTintColor); } } private void closeDragResizeListener() { Loading
packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt +1 −2 Original line number Diff line number Diff line Loading @@ -35,8 +35,7 @@ interface LaunchableView { * * Note that calls to [View.setTransitionVisibility] shouldn't be blocked. * * @param block whether we should block/postpone all calls to `setVisibility` and * `setTransitionVisibility`. * @param block whether we should block/postpone all calls to `setVisibility`. */ fun setShouldBlockVisibilityChanges(block: Boolean) } Loading
packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt +1 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ class RippleAnimation(private val config: RippleAnimationConfig) { private fun applyConfigToShader() { with(rippleShader) { setCenter(config.centerX, config.centerY) setMaxSize(config.maxWidth, config.maxHeight) rippleSize.setMaxSize(config.maxWidth, config.maxHeight) pixelDensity = config.pixelDensity color = ColorUtils.setAlphaComponent(config.color, config.opacity) sparkleStrength = config.sparkleStrength Loading
packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt +124 −21 Original line number Diff line number Diff line Loading @@ -15,9 +15,10 @@ */ package com.android.systemui.surfaceeffects.ripple import android.graphics.PointF import android.graphics.RuntimeShader import android.util.Log import android.util.MathUtils import androidx.annotation.VisibleForTesting import com.android.systemui.animation.Interpolators import com.android.systemui.surfaceeffects.shaderutil.SdfShaderLibrary import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary Loading @@ -44,6 +45,8 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : } // language=AGSL companion object { private val TAG = RippleShader::class.simpleName // Default fade in/ out values. The value range is [0,1]. const val DEFAULT_FADE_IN_START = 0f const val DEFAULT_FADE_OUT_END = 1f Loading Loading @@ -99,7 +102,7 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : vec4 main(vec2 p) { float sparkleRing = soften(roundedBoxRing(p-in_center, in_size, in_cornerRadius, in_thickness), in_blur); float inside = soften(sdRoundedBox(p-in_center, in_size * 1.2, in_cornerRadius), float inside = soften(sdRoundedBox(p-in_center, in_size * 1.25, in_cornerRadius), in_blur); float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175) * (1.-sparkleRing) * in_fadeSparkle; Loading Loading @@ -184,12 +187,17 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : setFloatUniform("in_center", x, y) } /** Max width of the ripple. */ private var maxSize: PointF = PointF() fun setMaxSize(width: Float, height: Float) { maxSize.x = width maxSize.y = height } /** * Blur multipliers for the ripple. * * <p>It interpolates from [blurStart] to [blurEnd] based on the [progress]. Increase number to * add more blur. */ var blurStart: Float = 1.25f var blurEnd: Float = 0.5f /** Size of the ripple. */ val rippleSize = RippleSize() /** * Linear progress of the ripple. Float value between [0, 1]. Loading @@ -209,15 +217,19 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : /** Progress with Standard easing curve applied. */ private var progress: Float = 0.0f set(value) { currentWidth = maxSize.x * value currentHeight = maxSize.y * value setFloatUniform("in_size", currentWidth, currentHeight) field = value setFloatUniform("in_thickness", maxSize.y * value * 0.5f) // radius should not exceed width and height values. setFloatUniform("in_cornerRadius", Math.min(maxSize.x, maxSize.y) * value) rippleSize.update(value) setFloatUniform("in_blur", MathUtils.lerp(1.25f, 0.5f, value)) setFloatUniform("in_size", rippleSize.currentWidth, rippleSize.currentHeight) setFloatUniform("in_thickness", rippleSize.currentHeight * 0.5f) // Corner radius is always max of the min between the current width and height. setFloatUniform( "in_cornerRadius", Math.min(rippleSize.currentWidth, rippleSize.currentHeight) ) setFloatUniform("in_blur", MathUtils.lerp(blurStart, blurEnd, value)) } /** Play time since the start of the effect. */ Loading Loading @@ -264,12 +276,6 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : setFloatUniform("in_pixelDensity", value) } var currentWidth: Float = 0f private set var currentHeight: Float = 0f private set /** Parameters that are used to fade in/ out of the sparkle ring. */ val sparkleRingFadeParams = FadeParams( Loading Loading @@ -342,4 +348,101 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : /** The endpoint of the fade out, given that the animation goes from 0 to 1. */ var fadeOutEnd: Float = DEFAULT_FADE_OUT_END, ) /** * Desired size of the ripple at a point t in [progress]. * * <p>Note that [progress] is curved and normalized. Below is an example usage: * SizeAtProgress(t= 0f, width= 0f, height= 0f), SizeAtProgress(t= 0.2f, width= 500f, height= * 700f), SizeAtProgress(t= 1f, width= 100f, height= 300f) * * <p>For simple ripple effects, you will want to use [setMaxSize] as it is translated into: * SizeAtProgress(t= 0f, width= 0f, height= 0f), SizeAtProgress(t= 1f, width= maxWidth, height= * maxHeight) */ data class SizeAtProgress( /** Time t in [0,1] progress range. */ var t: Float, /** Target width size of the ripple at time [t]. */ var width: Float, /** Target height size of the ripple at time [t]. */ var height: Float ) /** Updates and stores the ripple size. */ inner class RippleSize { @VisibleForTesting var sizes = mutableListOf<SizeAtProgress>() @VisibleForTesting var currentSizeIndex = 0 @VisibleForTesting val initialSize = SizeAtProgress(0f, 0f, 0f) var currentWidth: Float = 0f private set var currentHeight: Float = 0f private set /** * Sets the max size of the ripple. * * <p>Use this if the ripple shape simply changes linearly. */ fun setMaxSize(width: Float, height: Float) { setSizeAtProgresses(initialSize, SizeAtProgress(1f, width, height)) } /** * Sets the list of [sizes]. * * <p>Note that setting this clears the existing sizes. */ fun setSizeAtProgresses(vararg sizes: SizeAtProgress) { // Reset everything. this.sizes.clear() currentSizeIndex = 0 this.sizes.addAll(sizes) this.sizes.sortBy { it.t } } /** * Updates the current ripple size based on the progress. * * <p>Should be called when progress updates. */ fun update(progress: Float) { val targetIndex = updateTargetIndex(progress) val prevIndex = Math.max(targetIndex - 1, 0) val targetSize = sizes[targetIndex] val prevSize = sizes[prevIndex] val subProgress = subProgress(prevSize.t, targetSize.t, progress) currentWidth = targetSize.width * subProgress + prevSize.width currentHeight = targetSize.height * subProgress + prevSize.height } private fun updateTargetIndex(progress: Float): Int { if (sizes.isEmpty()) { // It could be empty on init. if (progress > 0f) { Log.e( TAG, "Did you forget to set the ripple size? Use [setMaxSize] or " + "[setSizeAtProgresses] before playing the animation." ) } // If there's no size is set, we set everything to 0. setSizeAtProgresses(initialSize) } var candidate = sizes[currentSizeIndex] while (progress > candidate.t) { currentSizeIndex = Math.min(currentSizeIndex + 1, sizes.size - 1) candidate = sizes[currentSizeIndex] } return currentSizeIndex } } }