Merge "Remove unnecessary transition logic from ImageWallpaper" into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-04-16 16:30:14 +00:00
committed by Android (Google) Code Review
11 changed files with 37 additions and 1040 deletions

View File

@@ -3,74 +3,9 @@ precision mediump float;
// The actual wallpaper texture.
uniform sampler2D uTexture;
// The 85th percenile for the luminance histogram of the image (a value between 0 and 1).
// This value represents the point in histogram that includes 85% of the pixels of the image.
uniform float uPer85;
// Reveal is the animation value that goes from 1 (the image is hidden) to 0 (the image is visible).
uniform float uReveal;
// The opacity of locked screen (constant value).
uniform float uAod2Opacity;
varying vec2 vTextureCoordinates;
/*
* Calculates the relative luminance of the pixel.
*/
vec3 luminosity(vec3 color) {
float lum = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
return vec3(lum);
}
vec4 transform(vec3 diffuse) {
// Getting the luminance for this pixel
vec3 lum = luminosity(diffuse);
/*
* while the reveal > per85, it shows the luminance image (B&W image)
* then when moving passed that value, the image gets colored.
*/
float trans = smoothstep(0., uPer85, uReveal);
diffuse = mix(diffuse, lum, trans);
// 'lower' value represents the capped 'reveal' value to the range [0, per85]
float selector = step(uPer85, uReveal);
float lower = mix(uReveal, uPer85, selector);
/*
* Remaps image:
* - from reveal=1 to reveal=per85 => lower=per85, diffuse=luminance
* That means that remaps black and white image pixel
* from a possible values of [0,1] to [per85, 1] (if the pixel is darker than per85,
* it's gonna be black, if it's between per85 and 1, it's gonna be gray
* and if it's 1 it's gonna be white).
* - from reveal=per85 to reveal=0 => lower=reveal, 'diffuse' changes from luminance to color
* That means that remaps each image pixel color (rgb)
* from a possible values of [0,1] to [lower, 1] (if the pixel color is darker than 'lower',
* it's gonna be 0, if it's between 'lower' and 1, it's gonna be remap to a value
* between 0 and 1 and if it's 1 it's gonna be 1).
* - if reveal=0 => lower=0, diffuse=color image
* The image is shown as it is, colored.
*/
vec3 remaps = smoothstep(lower, 1., diffuse);
// Interpolate between diffuse and remaps using reveal to avoid over saturation.
diffuse = mix(diffuse, remaps, uReveal);
/*
* Fades in the pixel value:
* - if reveal=1 => fadeInOpacity=0
* - from reveal=1 to reveal=per85 => 0<=fadeInOpacity<=1
* - if reveal>per85 => fadeInOpacity=1
*/
float fadeInOpacity = 1. - smoothstep(uPer85, 1., uReveal);
diffuse *= uAod2Opacity * fadeInOpacity;
return vec4(diffuse.r, diffuse.g, diffuse.b, 1.);
}
void main() {
// gets the pixel value of the wallpaper for this uv coordinates on screen.
vec4 fragColor = texture2D(uTexture, vTextureCoordinates);
gl_FragColor = transform(fragColor.rgb);
gl_FragColor = texture2D(uTexture, vTextureCoordinates);
}

View File

@@ -16,9 +16,6 @@
package com.android.systemui;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.HandlerThread;
@@ -27,17 +24,12 @@ import android.os.Trace;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.util.Size;
import android.view.DisplayInfo;
import android.view.SurfaceHolder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.glwallpaper.EglHelper;
import com.android.systemui.glwallpaper.GLWallpaperRenderer;
import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.DozeParameters;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -53,16 +45,12 @@ public class ImageWallpaper extends WallpaperService {
// We delayed destroy render context that subsequent render requests have chance to cancel it.
// This is to avoid destroying then recreating render context in a very short time.
private static final int DELAY_FINISH_RENDERING = 1000;
private static final int INTERVAL_WAIT_FOR_RENDERING = 100;
private static final int PATIENCE_WAIT_FOR_RENDERING = 10;
private static final boolean DEBUG = true;
private final DozeParameters mDozeParameters;
private static final boolean DEBUG = false;
private HandlerThread mWorker;
@Inject
public ImageWallpaper(DozeParameters dozeParameters) {
public ImageWallpaper() {
super();
mDozeParameters = dozeParameters;
}
@Override
@@ -74,7 +62,7 @@ public class ImageWallpaper extends WallpaperService {
@Override
public Engine onCreateEngine() {
return new GLEngine(this, mDozeParameters);
return new GLEngine();
}
@Override
@@ -84,7 +72,7 @@ public class ImageWallpaper extends WallpaperService {
mWorker = null;
}
class GLEngine extends Engine implements GLWallpaperRenderer.SurfaceProxy, StateListener {
class GLEngine extends Engine {
// Surface is rejected if size below a threshold on some devices (ie. 8px on elfin)
// set min to 64 px (CTS covers this), please refer to ag/4867989 for detail.
@VisibleForTesting
@@ -94,40 +82,15 @@ public class ImageWallpaper extends WallpaperService {
private GLWallpaperRenderer mRenderer;
private EglHelper mEglHelper;
private StatusBarStateController mController;
private final Runnable mFinishRenderingTask = this::finishRendering;
private boolean mShouldStopTransition;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
private final Object mMonitor = new Object();
@VisibleForTesting
boolean mIsHighEndGfx;
private boolean mDisplayNeedsBlanking;
private boolean mNeedTransition;
private boolean mNeedRedraw;
// This variable can only be accessed in synchronized block.
private boolean mWaitingForRendering;
GLEngine(Context context, DozeParameters dozeParameters) {
init(dozeParameters);
GLEngine() {
}
@VisibleForTesting
GLEngine(DozeParameters dozeParameters, Handler handler) {
GLEngine(Handler handler) {
super(SystemClock::elapsedRealtime, handler);
init(dozeParameters);
}
private void init(DozeParameters dozeParameters) {
mIsHighEndGfx = ActivityManager.isHighEndGfx();
mDisplayNeedsBlanking = dozeParameters.getDisplayNeedsBlanking();
mNeedTransition = false;
// We will preserve EGL context when we are in lock screen or aod
// to avoid janking in following transition, we need to release when back to home.
mController = Dependency.get(StatusBarStateController.class);
if (mController != null) {
mController.addCallback(this /* StateListener */);
}
}
@Override
@@ -135,9 +98,8 @@ public class ImageWallpaper extends WallpaperService {
mEglHelper = getEglHelperInstance();
// Deferred init renderer because we need to get wallpaper by display context.
mRenderer = getRendererInstance();
getDisplayContext().getDisplay().getDisplayInfo(mDisplayInfo);
setFixedSizeAllowed(true);
setOffsetNotificationsEnabled(mNeedTransition);
setOffsetNotificationsEnabled(false);
updateSurfaceSize();
}
@@ -146,7 +108,7 @@ public class ImageWallpaper extends WallpaperService {
}
ImageWallpaperRenderer getRendererInstance() {
return new ImageWallpaperRenderer(getDisplayContext(), this /* SurfaceProxy */);
return new ImageWallpaperRenderer(getDisplayContext());
}
private void updateSurfaceSize() {
@@ -157,79 +119,13 @@ public class ImageWallpaper extends WallpaperService {
holder.setFixedSize(width, height);
}
/**
* Check if necessary to stop transition with current wallpaper on this device. <br/>
* This should only be invoked after {@link #onSurfaceCreated(SurfaceHolder)}}
* is invoked since it needs display context and surface frame size.
* @return true if need to stop transition.
*/
@VisibleForTesting
boolean checkIfShouldStopTransition() {
int orientation = getDisplayContext().getResources().getConfiguration().orientation;
Rect frame = getSurfaceHolder().getSurfaceFrame();
Rect display = new Rect();
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
display.set(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
} else {
display.set(0, 0, mDisplayInfo.logicalHeight, mDisplayInfo.logicalWidth);
}
return mNeedTransition
&& (frame.width() < display.width() || frame.height() < display.height());
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep,
float yOffsetStep, int xPixelOffset, int yPixelOffset) {
if (mWorker == null) return;
mWorker.getThreadHandler().post(() -> mRenderer.updateOffsets(xOffset, yOffset));
}
@Override
public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
if (mWorker == null || !mNeedTransition) return;
final long duration = mShouldStopTransition ? 0 : animationDuration;
if (DEBUG) {
Log.d(TAG, "onAmbientModeChanged: inAmbient=" + inAmbientMode
+ ", duration=" + duration
+ ", mShouldStopTransition=" + mShouldStopTransition);
}
mWorker.getThreadHandler().post(
() -> mRenderer.updateAmbientMode(inAmbientMode, duration));
if (inAmbientMode && animationDuration == 0) {
// This means that we are transiting from home to aod, to avoid
// race condition between window visibility and transition,
// we don't return until the transition is finished. See b/136643341.
waitForBackgroundRendering();
}
}
@Override
public boolean shouldZoomOutWallpaper() {
return true;
}
private void waitForBackgroundRendering() {
synchronized (mMonitor) {
try {
mWaitingForRendering = true;
for (int patience = 1; mWaitingForRendering; patience++) {
mMonitor.wait(INTERVAL_WAIT_FOR_RENDERING);
mWaitingForRendering &= patience < PATIENCE_WAIT_FOR_RENDERING;
}
} catch (InterruptedException ex) {
} finally {
mWaitingForRendering = false;
}
}
}
@Override
public void onDestroy() {
if (mController != null) {
mController.removeCallback(this /* StateListener */);
}
mController = null;
mWorker.getThreadHandler().post(() -> {
mRenderer.finish();
mRenderer = null;
@@ -240,7 +136,6 @@ public class ImageWallpaper extends WallpaperService {
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
mShouldStopTransition = checkIfShouldStopTransition();
if (mWorker == null) return;
mWorker.getThreadHandler().post(() -> {
mEglHelper.init(holder, needSupportWideColorGamut());
@@ -251,32 +146,13 @@ public class ImageWallpaper extends WallpaperService {
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mWorker == null) return;
mWorker.getThreadHandler().post(() -> {
mRenderer.onSurfaceChanged(width, height);
mNeedRedraw = true;
});
mWorker.getThreadHandler().post(() -> mRenderer.onSurfaceChanged(width, height));
}
@Override
public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
if (mWorker == null) return;
if (DEBUG) {
Log.d(TAG, "onSurfaceRedrawNeeded: mNeedRedraw=" + mNeedRedraw);
}
mWorker.getThreadHandler().post(() -> {
if (mNeedRedraw) {
drawFrame();
mNeedRedraw = false;
}
});
}
@Override
public void onVisibilityChanged(boolean visible) {
if (DEBUG) {
Log.d(TAG, "wallpaper visibility changes: " + visible);
}
mWorker.getThreadHandler().post(this::drawFrame);
}
private void drawFrame() {
@@ -285,15 +161,6 @@ public class ImageWallpaper extends WallpaperService {
postRender();
}
@Override
public void onStatePostChange() {
// When back to home, we try to release EGL, which is preserved in lock screen or aod.
if (mWorker != null && mController.getState() == StatusBarState.SHADE) {
mWorker.getThreadHandler().post(this::scheduleFinishRendering);
}
}
@Override
public void preRender() {
// This method should only be invoked from worker thread.
Trace.beginSection("ImageWallpaper#preRender");
@@ -330,7 +197,6 @@ public class ImageWallpaper extends WallpaperService {
}
}
@Override
public void requestRender() {
// This method should only be invoked from worker thread.
Trace.beginSection("ImageWallpaper#requestRender");
@@ -355,27 +221,13 @@ public class ImageWallpaper extends WallpaperService {
}
}
@Override
public void postRender() {
// This method should only be invoked from worker thread.
Trace.beginSection("ImageWallpaper#postRender");
notifyWaitingThread();
scheduleFinishRendering();
Trace.endSection();
}
private void notifyWaitingThread() {
synchronized (mMonitor) {
if (mWaitingForRendering) {
try {
mWaitingForRendering = false;
mMonitor.notify();
} catch (IllegalMonitorStateException ex) {
}
}
}
}
private void cancelFinishRenderingTask() {
if (mWorker == null) return;
mWorker.getThreadHandler().removeCallbacks(mFinishRenderingTask);
@@ -391,18 +243,11 @@ public class ImageWallpaper extends WallpaperService {
Trace.beginSection("ImageWallpaper#finishRendering");
if (mEglHelper != null) {
mEglHelper.destroyEglSurface();
if (!needPreserveEglContext()) {
mEglHelper.destroyEglContext();
}
mEglHelper.destroyEglContext();
}
Trace.endSection();
}
private boolean needPreserveEglContext() {
return mNeedTransition && mController != null
&& mController.getState() == StatusBarState.KEYGUARD;
}
private boolean needSupportWideColorGamut() {
return mRenderer.isWcgContent();
}
@@ -411,16 +256,6 @@ public class ImageWallpaper extends WallpaperService {
protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
super.dump(prefix, fd, out, args);
out.print(prefix); out.print("Engine="); out.println(this);
out.print(prefix); out.print("isHighEndGfx="); out.println(mIsHighEndGfx);
out.print(prefix); out.print("displayNeedsBlanking=");
out.println(mDisplayNeedsBlanking);
out.print(prefix); out.print("displayInfo="); out.print(mDisplayInfo);
out.print(prefix); out.print("mNeedTransition="); out.println(mNeedTransition);
out.print(prefix); out.print("mShouldStopTransition=");
out.println(mShouldStopTransition);
out.print(prefix); out.print("StatusBarState=");
out.println(mController != null ? mController.getState() : "null");
out.print(prefix); out.print("valid surface=");
out.println(getSurfaceHolder() != null && getSurfaceHolder().getSurface() != null
? getSurfaceHolder().getSurface().isValid()

View File

@@ -48,20 +48,6 @@ public interface GLWallpaperRenderer {
*/
void onDrawFrame();
/**
* Notify ambient mode is changed.
* @param inAmbientMode true if in ambient mode.
* @param duration duration of transition.
*/
void updateAmbientMode(boolean inAmbientMode, long duration);
/**
* Notify the wallpaper offsets changed.
* @param xOffset offset along x axis.
* @param yOffset offset along y axis.
*/
void updateOffsets(float xOffset, float yOffset);
/**
* Ask renderer to report the surface size it needs.
*/
@@ -81,24 +67,4 @@ public interface GLWallpaperRenderer {
*/
void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args);
/**
* A proxy which owns surface holder.
*/
interface SurfaceProxy {
/**
* Ask proxy to start rendering frame to surface.
*/
void requestRender();
/**
* Ask proxy to prepare render context.
*/
void preRender();
/**
* Ask proxy to destroy render context.
*/
void postRender();
}
}

View File

@@ -33,7 +33,6 @@ import static android.opengl.GLES20.glUniform1i;
import static android.opengl.GLES20.glVertexAttribPointer;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.opengl.GLUtils;
import android.util.Log;
@@ -50,14 +49,9 @@ import java.nio.FloatBuffer;
class ImageGLWallpaper {
private static final String TAG = ImageGLWallpaper.class.getSimpleName();
static final String A_POSITION = "aPosition";
static final String A_TEXTURE_COORDINATES = "aTextureCoordinates";
static final String U_PER85 = "uPer85";
static final String U_REVEAL = "uReveal";
static final String U_AOD2OPACITY = "uAod2Opacity";
static final String U_TEXTURE = "uTexture";
private static final int HANDLE_UNDEFINED = -1;
private static final String A_POSITION = "aPosition";
private static final String A_TEXTURE_COORDINATES = "aTextureCoordinates";
private static final String U_TEXTURE = "uTexture";
private static final int POSITION_COMPONENT_COUNT = 2;
private static final int TEXTURE_COMPONENT_COUNT = 2;
private static final int BYTES_PER_FLOAT = 4;
@@ -88,14 +82,9 @@ class ImageGLWallpaper {
private int mAttrPosition;
private int mAttrTextureCoordinates;
private int mUniAod2Opacity;
private int mUniPer85;
private int mUniReveal;
private int mUniTexture;
private int mTextureId;
private float[] mCurrentTexCoordinate;
ImageGLWallpaper(ImageGLProgram program) {
mProgram = program;
@@ -135,31 +124,9 @@ class ImageGLWallpaper {
}
private void setupUniforms() {
mUniAod2Opacity = mProgram.getUniformHandle(U_AOD2OPACITY);
mUniPer85 = mProgram.getUniformHandle(U_PER85);
mUniReveal = mProgram.getUniformHandle(U_REVEAL);
mUniTexture = mProgram.getUniformHandle(U_TEXTURE);
}
int getHandle(String name) {
switch (name) {
case A_POSITION:
return mAttrPosition;
case A_TEXTURE_COORDINATES:
return mAttrTextureCoordinates;
case U_AOD2OPACITY:
return mUniAod2Opacity;
case U_PER85:
return mUniPer85;
case U_REVEAL:
return mUniReveal;
case U_TEXTURE:
return mUniTexture;
default:
return HANDLE_UNDEFINED;
}
}
void draw() {
glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
}
@@ -200,87 +167,6 @@ class ImageGLWallpaper {
glUniform1i(mUniTexture, 0);
}
/**
* This method adjust s(x-axis), t(y-axis) texture coordinates to get current display area
* of texture and will be used during transition.
* The adjustment happens if either the width or height of the surface is larger than
* corresponding size of the display area.
* If both width and height are larger than corresponding size of the display area,
* the adjustment will happen at both s, t side.
*
* @param surface The size of the surface.
* @param scissor The display area.
* @param xOffset The offset amount along s axis.
* @param yOffset The offset amount along t axis.
*/
void adjustTextureCoordinates(Rect surface, Rect scissor, float xOffset, float yOffset) {
mCurrentTexCoordinate = TEXTURES.clone();
if (surface == null || scissor == null) {
mTextureBuffer.put(mCurrentTexCoordinate);
mTextureBuffer.position(0);
return;
}
int surfaceWidth = surface.width();
int surfaceHeight = surface.height();
int scissorWidth = scissor.width();
int scissorHeight = scissor.height();
if (surfaceWidth > scissorWidth) {
// Calculate the new s pos in pixels.
float pixelS = (float) Math.round((surfaceWidth - scissorWidth) * xOffset);
// Calculate the s pos in texture coordinate.
float coordinateS = pixelS / surfaceWidth;
// Calculate the percentage occupied by the scissor width in surface width.
float surfacePercentageW = (float) scissorWidth / surfaceWidth;
// Need also consider the case if surface height is smaller than scissor height.
if (surfaceHeight < scissorHeight) {
// We will narrow the surface percentage to keep aspect ratio.
surfacePercentageW *= (float) surfaceHeight / scissorHeight;
}
// Determine the final s pos, also limit the legal s pos to prevent from out of range.
float s = coordinateS + surfacePercentageW > 1f ? 1f - surfacePercentageW : coordinateS;
// Traverse the s pos in texture coordinates array and adjust the s pos accordingly.
for (int i = 0; i < mCurrentTexCoordinate.length; i += 2) {
// indices 2, 4 and 6 are the end of s coordinates.
if (i == 2 || i == 4 || i == 6) {
mCurrentTexCoordinate[i] = Math.min(1f, s + surfacePercentageW);
} else {
mCurrentTexCoordinate[i] = s;
}
}
}
if (surfaceHeight > scissorHeight) {
// Calculate the new t pos in pixels.
float pixelT = (float) Math.round((surfaceHeight - scissorHeight) * yOffset);
// Calculate the t pos in texture coordinate.
float coordinateT = pixelT / surfaceHeight;
// Calculate the percentage occupied by the scissor height in surface height.
float surfacePercentageH = (float) scissorHeight / surfaceHeight;
// Need also consider the case if surface width is smaller than scissor width.
if (surfaceWidth < scissorWidth) {
// We will narrow the surface percentage to keep aspect ratio.
surfacePercentageH *= (float) surfaceWidth / scissorWidth;
}
// Determine the final t pos, also limit the legal t pos to prevent from out of range.
float t = coordinateT + surfacePercentageH > 1f ? 1f - surfacePercentageH : coordinateT;
// Traverse the t pos in texture coordinates array and adjust the t pos accordingly.
for (int i = 1; i < mCurrentTexCoordinate.length; i += 2) {
// indices 1, 3 and 11 are the end of t coordinates.
if (i == 1 || i == 3 || i == 11) {
mCurrentTexCoordinate[i] = Math.min(1f, t + surfacePercentageH);
} else {
mCurrentTexCoordinate[i] = t;
}
}
}
mTextureBuffer.put(mCurrentTexCoordinate);
mTextureBuffer.position(0);
}
/**
* Called to dump current state.
* @param prefix prefix.
@@ -289,17 +175,5 @@ class ImageGLWallpaper {
* @param args args.
*/
public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
StringBuilder sb = new StringBuilder();
sb.append('{');
if (mCurrentTexCoordinate != null) {
for (int i = 0; i < mCurrentTexCoordinate.length; i++) {
sb.append(mCurrentTexCoordinate[i]).append(',');
if (i == mCurrentTexCoordinate.length - 1) {
sb.deleteCharAt(sb.length() - 1);
}
}
}
sb.append('}');
out.print(prefix); out.print("mTexCoordinates="); out.println(sb.toString());
}
}

View File

@@ -1,246 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.glwallpaper;
import static com.android.systemui.glwallpaper.ImageWallpaperRenderer.WallpaperTexture;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.util.Log;
/**
* A helper class that computes threshold from a bitmap.
* Threshold will be computed each time the user picks a new image wallpaper.
*/
class ImageProcessHelper {
private static final String TAG = ImageProcessHelper.class.getSimpleName();
private static final float DEFAULT_THRESHOLD = 0.8f;
private static final float DEFAULT_OTSU_THRESHOLD = 0f;
private static final float MAX_THRESHOLD = 0.89f;
private static final int MSG_UPDATE_THRESHOLD = 1;
/**
* This color matrix will be applied to each pixel to get luminance from rgb by below formula:
* Luminance = .2126f * r + .7152f * g + .0722f * b.
*/
private static final float[] LUMINOSITY_MATRIX = new float[] {
.2126f, .0000f, .0000f, .0000f, .0000f,
.0000f, .7152f, .0000f, .0000f, .0000f,
.0000f, .0000f, .0722f, .0000f, .0000f,
.0000f, .0000f, .0000f, 1.000f, .0000f
};
private final Handler mHandler = new Handler(new Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_THRESHOLD:
mThreshold = (float) msg.obj;
return true;
default:
return false;
}
}
});
private float mThreshold = DEFAULT_THRESHOLD;
void start(WallpaperTexture texture) {
new ThresholdComputeTask(mHandler).execute(texture);
}
float getThreshold() {
return Math.min(mThreshold, MAX_THRESHOLD);
}
private static class ThresholdComputeTask extends AsyncTask<WallpaperTexture, Void, Float> {
private Handler mUpdateHandler;
ThresholdComputeTask(Handler handler) {
super(handler);
mUpdateHandler = handler;
}
@Override
protected Float doInBackground(WallpaperTexture... textures) {
WallpaperTexture texture = textures[0];
final float[] threshold = new float[] {DEFAULT_THRESHOLD};
if (texture == null) {
Log.e(TAG, "ThresholdComputeTask: WallpaperTexture not initialized");
return threshold[0];
}
texture.use(bitmap -> {
if (bitmap != null) {
threshold[0] = new Threshold().compute(bitmap);
} else {
Log.e(TAG, "ThresholdComputeTask: Can't get bitmap");
}
});
return threshold[0];
}
@Override
protected void onPostExecute(Float result) {
Message msg = mUpdateHandler.obtainMessage(MSG_UPDATE_THRESHOLD, result);
mUpdateHandler.sendMessage(msg);
}
}
private static class Threshold {
public float compute(Bitmap bitmap) {
Bitmap grayscale = toGrayscale(bitmap);
int[] histogram = getHistogram(grayscale);
boolean isSolidColor = isSolidColor(grayscale, histogram);
// We will see gray wallpaper during the transition if solid color wallpaper is set,
// please refer to b/130360362#comment16.
// As a result, we use Percentile85 rather than Otsus if a solid color wallpaper is set.
ThresholdAlgorithm algorithm = isSolidColor ? new Percentile85() : new Otsus();
return algorithm.compute(grayscale, histogram);
}
private Bitmap toGrayscale(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap grayscale = Bitmap.createBitmap(width, height, bitmap.getConfig(),
false /* hasAlpha */, bitmap.getColorSpace());
Canvas canvas = new Canvas(grayscale);
ColorMatrix cm = new ColorMatrix(LUMINOSITY_MATRIX);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(bitmap, new Matrix(), paint);
return grayscale;
}
private int[] getHistogram(Bitmap grayscale) {
int width = grayscale.getWidth();
int height = grayscale.getHeight();
// TODO: Fine tune the performance here, tracking on b/123615079.
int[] histogram = new int[256];
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = grayscale.getPixel(col, row);
int y = Color.red(pixel) + Color.green(pixel) + Color.blue(pixel);
histogram[y]++;
}
}
return histogram;
}
private boolean isSolidColor(Bitmap bitmap, int[] histogram) {
boolean solidColor = false;
int pixels = bitmap.getWidth() * bitmap.getHeight();
// In solid color case, only one element of histogram has value,
// which is pixel counts and the value of other elements should be 0.
for (int value : histogram) {
if (value != 0 && value != pixels) {
break;
}
if (value == pixels) {
solidColor = true;
break;
}
}
return solidColor;
}
}
private static class Percentile85 implements ThresholdAlgorithm {
@Override
public float compute(Bitmap bitmap, int[] histogram) {
float per85 = DEFAULT_THRESHOLD;
int pixelCount = bitmap.getWidth() * bitmap.getHeight();
float[] acc = new float[256];
for (int i = 0; i < acc.length; i++) {
acc[i] = (float) histogram[i] / pixelCount;
float prev = i == 0 ? 0f : acc[i - 1];
float next = acc[i];
float idx = (float) (i + 1) / 255;
float sum = prev + next;
if (prev < 0.85f && sum >= 0.85f) {
per85 = idx;
}
if (i > 0) {
acc[i] += acc[i - 1];
}
}
return per85;
}
}
private static class Otsus implements ThresholdAlgorithm {
@Override
public float compute(Bitmap bitmap, int[] histogram) {
float threshold = DEFAULT_OTSU_THRESHOLD;
float maxVariance = 0;
float pixelCount = bitmap.getWidth() * bitmap.getHeight();
float[] w = new float[2];
float[] m = new float[2];
float[] u = new float[2];
for (int i = 0; i < histogram.length; i++) {
m[1] += i * histogram[i];
}
w[1] = pixelCount;
for (int tonalValue = 0; tonalValue < histogram.length; tonalValue++) {
float dU;
float variance;
float numPixels = histogram[tonalValue];
float tmp = numPixels * tonalValue;
w[0] += numPixels;
w[1] -= numPixels;
if (w[0] == 0 || w[1] == 0) {
continue;
}
m[0] += tmp;
m[1] -= tmp;
u[0] = m[0] / w[0];
u[1] = m[1] / w[1];
dU = u[0] - u[1];
variance = w[0] * w[1] * dU * dU;
if (variance > maxVariance) {
threshold = (tonalValue + 1f) / histogram.length;
maxVariance = variance;
}
}
return threshold;
}
}
private interface ThresholdAlgorithm {
float compute(Bitmap bitmap, int[] histogram);
}
}

View File

@@ -1,126 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.glwallpaper;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.util.Log;
import com.android.systemui.Interpolators;
/**
* Use ValueAnimator and appropriate interpolator to control the progress of reveal transition.
* The transition will happen while getting awake and quit events.
*/
class ImageRevealHelper {
private static final String TAG = ImageRevealHelper.class.getSimpleName();
private static final float MAX_REVEAL = 0f;
private static final float MIN_REVEAL = 1f;
private static final boolean DEBUG = true;
private final ValueAnimator mAnimator;
private final RevealStateListener mRevealListener;
private float mReveal = MAX_REVEAL;
private boolean mAwake = false;
ImageRevealHelper(RevealStateListener listener) {
mRevealListener = listener;
mAnimator = ValueAnimator.ofFloat();
mAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mAnimator.addUpdateListener(animator -> {
mReveal = (float) animator.getAnimatedValue();
if (mRevealListener != null) {
mRevealListener.onRevealStateChanged();
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mIsCanceled;
@Override
public void onAnimationCancel(Animator animation) {
mIsCanceled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
if (!mIsCanceled && mRevealListener != null) {
if (DEBUG) {
Log.d(TAG, "transition end");
}
mRevealListener.onRevealEnd();
}
mIsCanceled = false;
}
@Override
public void onAnimationStart(Animator animation) {
if (mRevealListener != null) {
if (DEBUG) {
Log.d(TAG, "transition start");
}
mRevealListener.onRevealStart(true /* animate */);
}
}
});
}
public float getReveal() {
return mReveal;
}
void updateAwake(boolean awake, long duration) {
if (DEBUG) {
Log.d(TAG, "updateAwake: awake=" + awake + ", duration=" + duration);
}
mAnimator.cancel();
mAwake = awake;
if (duration == 0) {
// We are transiting from home to aod or aod to home directly,
// we don't need to do transition in these cases.
mReveal = mAwake ? MAX_REVEAL : MIN_REVEAL;
mRevealListener.onRevealStart(false /* animate */);
mRevealListener.onRevealStateChanged();
mRevealListener.onRevealEnd();
} else {
mAnimator.setDuration(duration);
mAnimator.setFloatValues(mReveal, mAwake ? MAX_REVEAL : MIN_REVEAL);
mAnimator.start();
}
}
/**
* A listener to trace value changes of reveal.
*/
public interface RevealStateListener {
/**
* Called back while reveal status changes.
*/
void onRevealStateChanged();
/**
* Called back while reveal starts.
*/
void onRevealStart(boolean animate);
/**
* Called back while reveal ends.
*/
void onRevealEnd();
}
}

View File

@@ -19,18 +19,14 @@ package com.android.systemui.glwallpaper;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glUniform1f;
import static android.opengl.GLES20.glViewport;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.Log;
import android.util.MathUtils;
import android.util.Size;
import android.view.DisplayInfo;
import com.android.systemui.R;
@@ -42,57 +38,24 @@ import java.util.function.Consumer;
/**
* A GL renderer for image wallpaper.
*/
public class ImageWallpaperRenderer implements GLWallpaperRenderer,
ImageRevealHelper.RevealStateListener {
public class ImageWallpaperRenderer implements GLWallpaperRenderer {
private static final String TAG = ImageWallpaperRenderer.class.getSimpleName();
private static final float SCALE_VIEWPORT_MIN = 1f;
private static final float SCALE_VIEWPORT_MAX = 1.1f;
private static final boolean DEBUG = true;
private static final boolean DEBUG = false;
private final ImageGLProgram mProgram;
private final ImageGLWallpaper mWallpaper;
private final ImageProcessHelper mImageProcessHelper;
private final ImageRevealHelper mImageRevealHelper;
private SurfaceProxy mProxy;
private final Rect mScissor;
private final Rect mSurfaceSize = new Rect();
private final Rect mViewport = new Rect();
private boolean mScissorMode;
private float mXOffset;
private float mYOffset;
private final WallpaperTexture mTexture;
public ImageWallpaperRenderer(Context context, SurfaceProxy proxy) {
public ImageWallpaperRenderer(Context context) {
final WallpaperManager wpm = context.getSystemService(WallpaperManager.class);
if (wpm == null) {
Log.w(TAG, "WallpaperManager not available");
}
mTexture = new WallpaperTexture(wpm);
DisplayInfo displayInfo = new DisplayInfo();
context.getDisplay().getDisplayInfo(displayInfo);
// We only do transition in portrait currently, b/137962047.
int orientation = context.getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
mScissor = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
} else {
mScissor = new Rect(0, 0, displayInfo.logicalHeight, displayInfo.logicalWidth);
}
mProxy = proxy;
mProgram = new ImageGLProgram(context);
mWallpaper = new ImageGLWallpaper(mProgram);
mImageProcessHelper = new ImageProcessHelper();
mImageRevealHelper = new ImageRevealHelper(this);
startProcessingImage();
}
protected void startProcessingImage() {
// Compute threshold of the image, this is an async work.
mImageProcessHelper.start(mTexture);
}
@Override
@@ -121,103 +84,26 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer,
@Override
public void onDrawFrame() {
float threshold = mImageProcessHelper.getThreshold();
float reveal = mImageRevealHelper.getReveal();
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_AOD2OPACITY), 1);
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_PER85), threshold);
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal);
glClear(GL_COLOR_BUFFER_BIT);
// We only need to scale viewport while doing transition.
if (mScissorMode) {
scaleViewport(reveal);
} else {
glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height());
}
glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height());
mWallpaper.useTexture();
mWallpaper.draw();
}
@Override
public void updateAmbientMode(boolean inAmbientMode, long duration) {
mImageRevealHelper.updateAwake(!inAmbientMode, duration);
}
@Override
public void updateOffsets(float xOffset, float yOffset) {
mXOffset = xOffset;
mYOffset = yOffset;
int left = (int) ((mSurfaceSize.width() - mScissor.width()) * xOffset);
int right = left + mScissor.width();
mScissor.set(left, mScissor.top, right, mScissor.bottom);
}
@Override
public Size reportSurfaceSize() {
mTexture.use(null);
mTexture.use(null /* consumer */);
mSurfaceSize.set(mTexture.getTextureDimensions());
return new Size(mSurfaceSize.width(), mSurfaceSize.height());
}
@Override
public void finish() {
mProxy = null;
}
private void scaleViewport(float reveal) {
int left = mScissor.left;
int top = mScissor.top;
int width = mScissor.width();
int height = mScissor.height();
// Interpolation between SCALE_VIEWPORT_MAX and SCALE_VIEWPORT_MIN by reveal.
float vpScaled = MathUtils.lerp(SCALE_VIEWPORT_MIN, SCALE_VIEWPORT_MAX, reveal);
// Calculate the offset amount from the lower left corner.
float offset = (SCALE_VIEWPORT_MIN - vpScaled) / 2;
// Change the viewport.
mViewport.set((int) (left + width * offset), (int) (top + height * offset),
(int) (width * vpScaled), (int) (height * vpScaled));
glViewport(mViewport.left, mViewport.top, mViewport.right, mViewport.bottom);
}
@Override
public void onRevealStateChanged() {
mProxy.requestRender();
}
@Override
public void onRevealStart(boolean animate) {
if (animate) {
mScissorMode = true;
// Use current display area of texture.
mWallpaper.adjustTextureCoordinates(mSurfaceSize, mScissor, mXOffset, mYOffset);
}
mProxy.preRender();
}
@Override
public void onRevealEnd() {
if (mScissorMode) {
mScissorMode = false;
// reset texture coordinates to use full texture.
mWallpaper.adjustTextureCoordinates(null, null, 0, 0);
// We need draw full texture back before finishing render.
mProxy.requestRender();
}
mProxy.postRender();
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
out.print(prefix); out.print("mProxy="); out.print(mProxy);
out.print(prefix); out.print("mSurfaceSize="); out.print(mSurfaceSize);
out.print(prefix); out.print("mScissor="); out.print(mScissor);
out.print(prefix); out.print("mViewport="); out.print(mViewport);
out.print(prefix); out.print("mScissorMode="); out.print(mScissorMode);
out.print(prefix); out.print("mXOffset="); out.print(mXOffset);
out.print(prefix); out.print("mYOffset="); out.print(mYOffset);
out.print(prefix); out.print("threshold="); out.print(mImageProcessHelper.getThreshold());
out.print(prefix); out.print("mReveal="); out.print(mImageRevealHelper.getReveal());
out.print(prefix); out.print("mWcgContent="); out.print(isWcgContent());
mWallpaper.dump(prefix, fd, out, args);
}

View File

@@ -16,7 +16,6 @@
package com.android.systemui;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Mockito.doReturn;
@@ -32,19 +31,16 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Handler;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Size;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.SurfaceHolder;
import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
import com.android.systemui.statusbar.phone.DozeParameters;
import org.junit.Before;
import org.junit.Test;
@@ -72,8 +68,6 @@ public class ImageWallpaperTest extends SysuiTestCase {
@Mock
private Bitmap mWallpaperBitmap;
@Mock
private DozeParameters mDozeParam;
@Mock
private Handler mHandler;
private CountDownLatch mEventCountdown;
@@ -100,14 +94,13 @@ public class ImageWallpaperTest extends SysuiTestCase {
when(wallpaperManager.getBitmap(false)).thenReturn(mWallpaperBitmap);
when(mWallpaperBitmap.getColorSpace()).thenReturn(ColorSpace.get(ColorSpace.Named.SRGB));
when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
when(mDozeParam.getDisplayNeedsBlanking()).thenReturn(false);
}
private ImageWallpaper createImageWallpaper() {
return new ImageWallpaper(mDozeParam) {
return new ImageWallpaper() {
@Override
public Engine onCreateEngine() {
return new GLEngine(mDozeParam, mHandler) {
return new GLEngine(mHandler) {
@Override
public Context getDisplayContext() {
return mMockContext;
@@ -130,75 +123,52 @@ public class ImageWallpaperTest extends SysuiTestCase {
};
}
private ImageWallpaperRenderer createImageWallpaperRenderer(ImageWallpaper.GLEngine engine) {
return new ImageWallpaperRenderer(mMockContext, engine) {
@Override
public void startProcessingImage() {
// No - Op
}
};
}
@Test
public void testBitmapWallpaper_normal() {
// Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
// Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH.
// Finally, we assert the transition will not be stopped.
verifySurfaceSizeAndAssertTransition(DISPLAY_WIDTH /* bmpWidth */,
verifySurfaceSize(DISPLAY_WIDTH /* bmpWidth */,
DISPLAY_WIDTH /* bmpHeight */,
DISPLAY_WIDTH /* surfaceWidth */,
DISPLAY_WIDTH /* surfaceHeight */,
false /* assertion */);
DISPLAY_WIDTH /* surfaceHeight */);
}
@Test
public void testBitmapWallpaper_low_resolution() {
// Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
// Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT.
// Finally, we assert the transition will be stopped.
verifySurfaceSizeAndAssertTransition(LOW_BMP_WIDTH /* bmpWidth */,
verifySurfaceSize(LOW_BMP_WIDTH /* bmpWidth */,
LOW_BMP_HEIGHT /* bmpHeight */,
LOW_BMP_WIDTH /* surfaceWidth */,
LOW_BMP_HEIGHT /* surfaceHeight */,
false /* assertion */);
LOW_BMP_HEIGHT /* surfaceHeight */);
}
@Test
public void testBitmapWallpaper_too_small() {
// Will use a image wallpaper with dimensions INVALID_BMP_WIDTH x INVALID_BMP_HEIGHT.
// Then we expect the surface size will be also MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT.
// Finally, we assert the transition will be stopped.
verifySurfaceSizeAndAssertTransition(INVALID_BMP_WIDTH /* bmpWidth */,
verifySurfaceSize(INVALID_BMP_WIDTH /* bmpWidth */,
INVALID_BMP_HEIGHT /* bmpHeight */,
ImageWallpaper.GLEngine.MIN_SURFACE_WIDTH /* surfaceWidth */,
ImageWallpaper.GLEngine.MIN_SURFACE_HEIGHT /* surfaceHeight */,
false /* assertion */);
ImageWallpaper.GLEngine.MIN_SURFACE_HEIGHT /* surfaceHeight */);
}
private void verifySurfaceSizeAndAssertTransition(int bmpWidth, int bmpHeight,
int surfaceWidth, int surfaceHeight, boolean assertion) {
private void verifySurfaceSize(int bmpWidth, int bmpHeight,
int surfaceWidth, int surfaceHeight) {
ImageWallpaper.GLEngine wallpaperEngine =
(ImageWallpaper.GLEngine) createImageWallpaper().onCreateEngine();
ImageWallpaper.GLEngine engineSpy = spy(wallpaperEngine);
when(engineSpy.mIsHighEndGfx).thenReturn(true);
when(mWallpaperBitmap.getWidth()).thenReturn(bmpWidth);
when(mWallpaperBitmap.getHeight()).thenReturn(bmpHeight);
ImageWallpaperRenderer renderer = createImageWallpaperRenderer(engineSpy);
ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mMockContext);
doReturn(renderer).when(engineSpy).getRendererInstance();
engineSpy.onCreate(engineSpy.getSurfaceHolder());
verify(mSurfaceHolder, times(1)).setFixedSize(surfaceWidth, surfaceHeight);
assertWithMessage("setFixedSizeAllowed should have been called.").that(
mEventCountdown.getCount()).isEqualTo(0);
Size frameSize = renderer.reportSurfaceSize();
Rect frame = new Rect(0, 0, frameSize.getWidth(), frameSize.getHeight());
when(mSurfaceHolder.getSurfaceFrame()).thenReturn(frame);
assertThat(engineSpy.checkIfShouldStopTransition()).isEqualTo(assertion);
// destroy
}
}

View File

@@ -40,6 +40,7 @@ import com.android.systemui.SysuiTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -84,22 +85,17 @@ public class EglHelperTest extends SysuiTestCase {
}
@Test
public void testInit_finish() {
public void testInit_normal() {
mEglHelper.init(mSurfaceHolder, false /* wideColorGamut */);
assertThat(mEglHelper.hasEglDisplay()).isTrue();
assertThat(mEglHelper.hasEglContext()).isTrue();
assertThat(mEglHelper.hasEglSurface()).isTrue();
verify(mEglHelper).askCreatingEglWindowSurface(
any(SurfaceHolder.class), eq(null), anyInt());
mEglHelper.finish();
assertThat(mEglHelper.hasEglSurface()).isFalse();
assertThat(mEglHelper.hasEglContext()).isFalse();
assertThat(mEglHelper.hasEglDisplay()).isFalse();
}
@Test
public void testInit_finish_wide_gamut() {
public void testInit_wide_gamut() {
// In EglHelper, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
doReturn(0x3490).when(mEglHelper).getWcgCapability();
// In EglHelper, KHR_GL_COLOR_SPACE = "EGL_KHR_gl_colorspace";
@@ -113,10 +109,10 @@ public class EglHelperTest extends SysuiTestCase {
.askCreatingEglWindowSurface(any(SurfaceHolder.class), ac.capture(), anyInt());
assertThat(ac.getValue()).isNotNull();
assertThat(ac.getValue()).isEqualTo(expectedArgument);
mEglHelper.finish();
}
@Test
@Ignore
public void testFinish_shouldNotCrash() {
mEglHelper.terminateEglDisplay();
assertThat(mEglHelper.hasEglDisplay()).isFalse();

View File

@@ -1,73 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.glwallpaper;
import static com.google.common.truth.Truth.assertThat;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class ImageRevealHelperTest extends SysuiTestCase {
static final int ANIMATION_DURATION = 500;
ImageRevealHelper mImageRevealHelper;
ImageRevealHelper.RevealStateListener mRevealStateListener;
@Before
public void setUp() throws Exception {
mRevealStateListener = new ImageRevealHelper.RevealStateListener() {
@Override
public void onRevealStateChanged() {
// no-op
}
@Override
public void onRevealStart(boolean animate) {
// no-op
}
@Override
public void onRevealEnd() {
// no-op
}
};
mImageRevealHelper = new ImageRevealHelper(mRevealStateListener);
}
@Test
public void testBiometricAuthUnlockAnimateImageRevealState_shouldNotBlackoutScreen() {
assertThat(mImageRevealHelper.getReveal()).isEqualTo(0f);
mImageRevealHelper.updateAwake(true /* awake */, ANIMATION_DURATION);
assertThat(mImageRevealHelper.getReveal()).isEqualTo(0f);
// When device unlock through Biometric, should not show reveal transition
mImageRevealHelper.updateAwake(false /* awake */, 0);
assertThat(mImageRevealHelper.getReveal()).isEqualTo(1f);
}
}

View File

@@ -16,8 +16,6 @@
package com.android.systemui.glwallpaper;
import static com.android.systemui.glwallpaper.GLWallpaperRenderer.SurfaceProxy;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
@@ -48,30 +46,12 @@ import java.util.Set;
public class ImageWallpaperRendererTest extends SysuiTestCase {
private WallpaperManager mWpmSpy;
private SurfaceProxy mSurfaceProxy;
@Before
public void setUp() throws Exception {
final WallpaperManager wpm = mContext.getSystemService(WallpaperManager.class);
mWpmSpy = spy(wpm);
mContext.addMockSystemService(WallpaperManager.class, mWpmSpy);
mSurfaceProxy = new SurfaceProxy() {
@Override
public void requestRender() {
// NO-op
}
@Override
public void preRender() {
// No-op
}
@Override
public void postRender() {
// No-op
}
};
}
@Test
@@ -91,12 +71,12 @@ public class ImageWallpaperRendererTest extends SysuiTestCase {
doReturn(supportedWideGamuts).when(cmProxySpy).getSupportedColorSpaces();
mWpmSpy.setBitmap(p3Bitmap);
ImageWallpaperRenderer rendererP3 = new ImageWallpaperRenderer(mContext, mSurfaceProxy);
ImageWallpaperRenderer rendererP3 = new ImageWallpaperRenderer(mContext);
rendererP3.reportSurfaceSize();
assertThat(rendererP3.isWcgContent()).isTrue();
mWpmSpy.setBitmap(srgbBitmap);
ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mContext, mSurfaceProxy);
ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mContext);
assertThat(renderer.isWcgContent()).isFalse();
} finally {
srgbBitmap.recycle();