Merge "Revert "Render ImageWallpaper with OpenGL ES and apply visual effects.""

This commit is contained in:
TreeHugger Robot
2019-02-07 02:02:34 +00:00
committed by Android (Google) Code Review
12 changed files with 9 additions and 968 deletions

View File

@@ -22,11 +22,6 @@
android:sharedUserId="android.uid.systemui"
coreApp="true">
<!-- Using OpenGL ES 2.0 -->
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<!-- SysUI must be the one to define this permission; its name is
referenced by the core OS. -->
<permission android:name="android.permission.systemui.IDENTITY"

View File

@@ -1,33 +0,0 @@
precision mediump float;
uniform sampler2D uTexture;
uniform float uCenterReveal;
uniform float uReveal;
uniform float uAod2Opacity;
uniform int uAodMode;
varying vec2 vTextureCoordinates;
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) {
// TODO: Add well comments here, tracking on b/123615467.
vec3 lum = luminosity(diffuse);
diffuse = mix(diffuse, lum, smoothstep(0., uCenterReveal, uReveal));
float val = mix(uReveal, uCenterReveal, step(uCenterReveal, uReveal));
diffuse = smoothstep(val, 1.0, diffuse);
diffuse *= uAod2Opacity * (1. - smoothstep(uCenterReveal, 1., uReveal));
return vec4(diffuse.r, diffuse.g, diffuse.b, 1.);
}
void main() {
vec4 fragColor = texture2D(uTexture, vTextureCoordinates);
// TODO: Remove the branch logic here, tracking on b/123615467.
if (uAodMode != 0) {
gl_FragColor = transform(fragColor.rgb);
} else {
gl_FragColor = fragColor;
}
}

View File

@@ -1,8 +0,0 @@
attribute vec4 aPosition;
attribute vec2 aTextureCoordinates;
varying vec2 vTextureCoordinates;
void main() {
vTextureCoordinates = aTextureCoordinates;
gl_Position = aPosition;
}

View File

@@ -19,11 +19,8 @@ package com.android.systemui;
import static android.view.Display.DEFAULT_DISPLAY;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.RecordingCanvas;
@@ -31,9 +28,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
import android.opengl.GLSurfaceView;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Trace;
import android.service.wallpaper.WallpaperService;
@@ -44,7 +39,6 @@ import android.view.Surface;
import android.view.SurfaceHolder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -57,17 +51,12 @@ import java.io.PrintWriter;
public class ImageWallpaper extends WallpaperService {
private static final String TAG = "ImageWallpaper";
private static final String GL_LOG_TAG = "ImageWallpaperGL";
// TODO: Testing purpose, need to remove later, b/123616712.
private static final String SENSOR_EVENT_AWAKE = "systemui.test.event.awake";
// TODO: Testing purpose, need to remove later, b/123616712.
private static final String SENSOR_EVENT_SLEEP = "systemui.test.event.sleep";
private static final boolean DEBUG = false;
private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu";
private static final long DELAY_FORGET_WALLPAPER = 5000;
private WallpaperManager mWallpaperManager;
private DrawableEngine mEngine;
private GLEngine mGlEngine;
@Override
public void onCreate() {
@@ -84,112 +73,10 @@ public class ImageWallpaper extends WallpaperService {
@Override
public Engine onCreateEngine() {
mGlEngine = new GLEngine(this);
return mGlEngine;
mEngine = new DrawableEngine();
return mEngine;
}
class GLEngine extends Engine {
private GLWallpaperSurfaceView mWallpaperSurfaceView;
GLEngine(Context context) {
mWallpaperSurfaceView = new GLWallpaperSurfaceView(context);
mWallpaperSurfaceView.setRenderer(
new ImageWallpaperRenderer(context, mWallpaperSurfaceView));
mWallpaperSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setOffsetNotificationsEnabled(true);
}
@Override
public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
if (mWallpaperSurfaceView != null) {
mWallpaperSurfaceView.notifyAmbientModeChanged(inAmbientMode);
}
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep,
float yOffsetStep, int xPixelOffset, int yPixelOffset) {
if (mWallpaperSurfaceView != null) {
mWallpaperSurfaceView.notifyOffsetsChanged(xOffset, yOffset);
}
}
private class GLWallpaperSurfaceView extends GLSurfaceView implements ImageGLView {
private SensorEventListener mEventListener;
private WallpaperStatusListener mWallpaperChangedListener;
// TODO: Testing purpose, need to remove later, b/123616712.
/**
* For testing only: adb shell am broadcast -a <INTENT>
*/
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
switch (intent.getAction()) {
case SENSOR_EVENT_AWAKE:
notifySensorEvents(true);
break;
case SENSOR_EVENT_SLEEP:
notifySensorEvents(false);
break;
}
}
};
GLWallpaperSurfaceView(Context context) {
super(context);
setEGLContextClientVersion(2);
// TODO: Testing purpose, need to remove later, b/123616712.
if (Build.IS_DEBUGGABLE) {
IntentFilter filter = new IntentFilter();
filter.addAction(SENSOR_EVENT_AWAKE);
filter.addAction(SENSOR_EVENT_SLEEP);
registerReceiver(mReceiver, filter);
}
}
@Override
public SurfaceHolder getHolder() {
return getSurfaceHolder();
}
@Override
public void setRenderer(Renderer renderer) {
super.setRenderer(renderer);
mEventListener = (SensorEventListener) renderer;
mWallpaperChangedListener = (WallpaperStatusListener) renderer;
}
private void notifySensorEvents(boolean reach) {
if (mEventListener != null) {
mEventListener.onSensorEvent(reach);
}
}
private void notifyAmbientModeChanged(boolean inAmbient) {
if (mWallpaperChangedListener != null) {
mWallpaperChangedListener.onAmbientModeChanged(inAmbient);
}
}
private void notifyOffsetsChanged(float xOffset, float yOffset) {
if (mWallpaperChangedListener != null) {
mWallpaperChangedListener.onOffsetsChanged(
xOffset, yOffset, getHolder().getSurfaceFrame());
}
}
@Override
public void render() {
requestRender();
}
}
}
// TODO: Remove this engine, tracking on b/123617158.
class DrawableEngine extends Engine {
private final Runnable mUnloadWallpaperCallback = () -> {
unloadWallpaper(false /* forgetSize */);
@@ -677,46 +564,4 @@ public class ImageWallpaper extends WallpaperService {
}
}
}
/**
* A listener to trace sensor event.
*/
public interface SensorEventListener {
/**
* Called back while sensor event comes.
* @param reach The status of sensor.
*/
void onSensorEvent(boolean reach);
}
/**
* A listener to trace status of image wallpaper.
*/
public interface WallpaperStatusListener {
/**
* Called back while ambient mode changes.
* @param inAmbientMode true if is in ambient mode, false otherwise.
*/
void onAmbientModeChanged(boolean inAmbientMode);
/**
* Called back while wallpaper offsets.
* @param xOffset The offset portion along x.
* @param yOffset The offset portion along y.
*/
void onOffsetsChanged(float xOffset, float yOffset, Rect frame);
}
/**
* An abstraction for view of GLRenderer.
*/
public interface ImageGLView {
/**
* Ask the view to render.
*/
void render();
}
}

View File

@@ -1,115 +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 android.opengl.GLES20.GL_FRAGMENT_SHADER;
import static android.opengl.GLES20.GL_VERTEX_SHADER;
import static android.opengl.GLES20.glAttachShader;
import static android.opengl.GLES20.glCompileShader;
import static android.opengl.GLES20.glCreateProgram;
import static android.opengl.GLES20.glCreateShader;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glLinkProgram;
import static android.opengl.GLES20.glShaderSource;
import static android.opengl.GLES20.glUseProgram;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* This class takes charge of linking shader codes and then return a handle for OpenGL ES program.
*/
class ImageGLProgram {
private static final String TAG = ImageGLProgram.class.getSimpleName();
private Context mContext;
private int mProgramHandle;
ImageGLProgram(Context context) {
mContext = context.getApplicationContext();
}
private int loadShaderProgram(int vertexId, int fragmentId) {
final String vertexSrc = getShaderResource(vertexId);
final String fragmentSrc = getShaderResource(fragmentId);
final int vertexHandle = getShaderHandle(GL_VERTEX_SHADER, vertexSrc);
final int fragmentHandle = getShaderHandle(GL_FRAGMENT_SHADER, fragmentSrc);
return getProgramHandle(vertexHandle, fragmentHandle);
}
private String getShaderResource(int shaderId) {
Resources res = mContext.getResources();
StringBuilder code = new StringBuilder();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(res.openRawResource(shaderId)))) {
String nextLine;
while ((nextLine = reader.readLine()) != null) {
code.append(nextLine).append("\n");
}
} catch (IOException | Resources.NotFoundException ex) {
Log.d(TAG, "Can not read the shader source", ex);
code = null;
}
return code == null ? "" : code.toString();
}
private int getShaderHandle(int type, String src) {
final int shader = glCreateShader(type);
if (shader == 0) {
Log.d(TAG, "Create shader failed, type=" + type);
return 0;
}
glShaderSource(shader, src);
glCompileShader(shader);
return shader;
}
private int getProgramHandle(int vertexHandle, int fragmentHandle) {
final int program = glCreateProgram();
if (program == 0) {
Log.d(TAG, "Can not create OpenGL ES program");
return 0;
}
glAttachShader(program, vertexHandle);
glAttachShader(program, fragmentHandle);
glLinkProgram(program);
return program;
}
boolean useGLProgram(int vertexResId, int fragmentResId) {
mProgramHandle = loadShaderProgram(vertexResId, fragmentResId);
glUseProgram(mProgramHandle);
return true;
}
int getAttributeHandle(String name) {
return glGetAttribLocation(mProgramHandle, name);
}
int getUniformHandle(String name) {
return glGetUniformLocation(mProgramHandle, name);
}
}

View File

@@ -1,245 +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 android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_LINEAR;
import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
import static android.opengl.GLES20.GL_TRIANGLES;
import static android.opengl.GLES20.glActiveTexture;
import static android.opengl.GLES20.glBindTexture;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGenTextures;
import static android.opengl.GLES20.glTexParameteri;
import static android.opengl.GLES20.glUniform1i;
import static android.opengl.GLES20.glVertexAttribPointer;
import android.graphics.Bitmap;
import android.opengl.GLUtils;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
/**
* This class takes charge of the geometry data like vertices and texture coordinates.
* It delivers these data to opengl runtime and triggers draw calls if necessary.
*/
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_CENTER_REVEAL = "uCenterReveal";
static final String U_REVEAL = "uReveal";
static final String U_AOD2OPACITY = "uAod2Opacity";
static final String U_TEXTURE = "uTexture";
static final String U_AOD_MODE = "uAodMode";
private static final int HANDLE_UNDEFINED = -1;
private static final int POSITION_COMPONENT_COUNT = 2;
private static final int TEXTURE_COMPONENT_COUNT = 2;
private static final int BYTES_PER_FLOAT = 4;
// Vertices to define the square with 2 triangles.
private static final float[] VERTICES = {
-1.0f, -1.0f,
+1.0f, -1.0f,
+1.0f, +1.0f,
+1.0f, +1.0f,
-1.0f, +1.0f,
-1.0f, -1.0f
};
// Texture coordinates that maps to vertices.
private static final float[] TEXTURES = {
0f, 1f,
1f, 1f,
1f, 0f,
1f, 0f,
0f, 0f,
0f, 1f
};
private final FloatBuffer mVertexBuffer;
private final FloatBuffer mTextureBuffer;
private final ImageGLProgram mProgram;
private int mAttrPosition;
private int mAttrTextureCoordinates;
private int mUniAod2Opacity;
private int mUniAodMode;
private int mUniCenterReveal;
private int mUniReveal;
private int mUniTexture;
private int mTextureId;
ImageGLWallpaper(ImageGLProgram program) {
mProgram = program;
// Create an float array in opengles runtime (native) and put vertex data.
mVertexBuffer = ByteBuffer.allocateDirect(VERTICES.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
mVertexBuffer.put(VERTICES);
mVertexBuffer.position(0);
// Create an float array in opengles runtime (native) and put texture data.
mTextureBuffer = ByteBuffer.allocateDirect(TEXTURES.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
mTextureBuffer.put(TEXTURES);
mTextureBuffer.position(0);
}
void setup() {
setupAttributes();
setupUniforms();
}
private void setupAttributes() {
mAttrPosition = mProgram.getAttributeHandle(A_POSITION);
mVertexBuffer.position(0);
glVertexAttribPointer(mAttrPosition, POSITION_COMPONENT_COUNT, GL_FLOAT,
false, 0, mVertexBuffer);
glEnableVertexAttribArray(mAttrPosition);
mAttrTextureCoordinates = mProgram.getAttributeHandle(A_TEXTURE_COORDINATES);
mTextureBuffer.position(0);
glVertexAttribPointer(mAttrTextureCoordinates, TEXTURE_COMPONENT_COUNT, GL_FLOAT,
false, 0, mTextureBuffer);
glEnableVertexAttribArray(mAttrTextureCoordinates);
}
private void setupUniforms() {
mUniAod2Opacity = mProgram.getUniformHandle(U_AOD2OPACITY);
mUniAodMode = mProgram.getUniformHandle(U_AOD_MODE);
mUniCenterReveal = mProgram.getUniformHandle(U_CENTER_REVEAL);
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_AOD_MODE:
return mUniAodMode;
case U_CENTER_REVEAL:
return mUniCenterReveal;
case U_REVEAL:
return mUniReveal;
case U_TEXTURE:
return mUniTexture;
default:
return HANDLE_UNDEFINED;
}
}
void draw() {
glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
}
void setupTexture(Bitmap bitmap) {
final int[] tids = new int[1];
if (bitmap == null) {
Log.w(TAG, "setupTexture: invalid bitmap");
return;
}
// Generate one texture object and store the id in tids[0].
glGenTextures(1, tids, 0);
if (tids[0] == 0) {
Log.w(TAG, "setupTexture: glGenTextures() failed");
return;
}
// Bind a named texture to a texturing target.
glBindTexture(GL_TEXTURE_2D, tids[0]);
// Load the bitmap data and copy it over into the texture object that is currently bound.
GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
// Use bilinear texture filtering when minification.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Use bilinear texture filtering when magnification.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
mTextureId = tids[0];
}
void useTexture() {
// Set the active texture unit to texture unit 0.
glActiveTexture(GL_TEXTURE0);
// Bind the texture to this unit.
glBindTexture(GL_TEXTURE_2D, mTextureId);
// Let the texture sampler in fragment shader to read form this texture unit.
glUniform1i(mUniTexture, 0);
}
void adjustTextureCoordinates(Bitmap bitmap, int surfaceWidth, int surfaceHeight,
float xOffset, float yOffset) {
if (bitmap == null) {
Log.d(TAG, "adjustTextureCoordinates: invalid bitmap");
return;
}
float ratioW = 1f;
float ratioH = 1f;
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
boolean adjustWidth = bitmapWidth > surfaceWidth;
if (adjustWidth) {
ratioW = (float) surfaceWidth / bitmapWidth;
float referenceX = xOffset + ratioW > 1f ? 1f - ratioW : xOffset;
for (int i = 0; i < TEXTURES.length; i += 2) {
if (i == 2 || i == 4 || i == 6) {
TEXTURES[i] = Math.min(1f, referenceX + ratioW);
} else {
TEXTURES[i] = referenceX;
}
}
}
boolean adjustHeight = bitmapHeight > surfaceHeight;
if (adjustHeight) {
ratioH = (float) surfaceHeight / bitmapHeight;
float referenceY = yOffset + ratioH > 1f ? 1f - ratioH : yOffset;
for (int i = 1; i < TEXTURES.length; i += 2) {
if (i == 1 || i == 3 || i == 11) {
TEXTURES[i] = Math.min(1f, referenceY + ratioH);
} else {
TEXTURES[i] = referenceY;
}
}
}
if (adjustWidth || adjustHeight) {
mTextureBuffer.put(TEXTURES);
mTextureBuffer.position(0);
}
}
}

View File

@@ -1,144 +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.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 histogram and percentile 85 from a bitmap.
* Percentile 85 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_PER85 = 0.8f;
private static final int MSG_UPDATE_PER85 = 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_PER85:
mPer85 = (float) msg.obj;
return true;
default:
return false;
}
}
});
private float mPer85 = DEFAULT_PER85;
void startComputingPercentile85(Bitmap bitmap) {
new Per85ComputeTask(mHandler).execute(bitmap);
}
float getPercentile85() {
return mPer85;
}
private static class Per85ComputeTask extends AsyncTask<Bitmap, Void, Float> {
private Handler mUpdateHandler;
Per85ComputeTask(Handler handler) {
super(handler);
mUpdateHandler = handler;
}
@Override
protected Float doInBackground(Bitmap... bitmaps) {
Bitmap bitmap = bitmaps[0];
if (bitmap != null) {
int[] histogram = processHistogram(bitmap);
return computePercentile85(bitmap, histogram);
}
Log.e(TAG, "Per85ComputeTask: Can't get bitmap");
return DEFAULT_PER85;
}
@Override
protected void onPostExecute(Float result) {
Message msg = mUpdateHandler.obtainMessage(MSG_UPDATE_PER85, result);
mUpdateHandler.sendMessage(msg);
}
private int[] processHistogram(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap target = Bitmap.createBitmap(width, height, bitmap.getConfig());
Canvas canvas = new Canvas(target);
ColorMatrix cm = new ColorMatrix(LUMINOSITY_MATRIX);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(bitmap, new Matrix(), paint);
// 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 = target.getPixel(col, row);
int y = Color.red(pixel) + Color.green(pixel) + Color.blue(pixel);
histogram[y]++;
}
}
return histogram;
}
private float computePercentile85(Bitmap bitmap, int[] histogram) {
float per85 = DEFAULT_PER85;
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;
}
}
}

View File

@@ -1,103 +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 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 int REVEAL_DURATION = 1000;
private final ValueAnimator mAnimator;
private final RevealStateListener mRevealListener;
private float mReveal = MIN_REVEAL;
private boolean mAwake = false;
ImageRevealHelper(RevealStateListener listener) {
mRevealListener = listener;
mAnimator = ValueAnimator.ofFloat();
mAnimator.setDuration(REVEAL_DURATION);
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) {
mAwake = !mAwake;
}
mIsCanceled = false;
}
});
}
private void animate() {
mAnimator.cancel();
mAnimator.setFloatValues(mReveal, !mAwake ? MIN_REVEAL : MAX_REVEAL);
mAnimator.start();
}
public float getReveal() {
return mReveal;
}
public boolean isAwake() {
return mAwake;
}
void updateAwake(boolean awake) {
mAwake = awake;
animate();
}
void sleep() {
mReveal = MIN_REVEAL;
mAwake = false;
}
/**
* A listener to trace value changes of reveal.
*/
public interface RevealStateListener {
/**
* Called back while reveal status changes.
*/
void onRevealStateChanged();
}
}

View File

@@ -1,153 +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 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.glUniform1i;
import static android.opengl.GLES20.glViewport;
import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.opengl.GLSurfaceView;
import android.util.Log;
import com.android.systemui.ImageWallpaper;
import com.android.systemui.ImageWallpaper.ImageGLView;
import com.android.systemui.R;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* A GL renderer for image wallpaper.
*/
public class ImageWallpaperRenderer implements GLSurfaceView.Renderer,
ImageWallpaper.SensorEventListener, ImageWallpaper.WallpaperStatusListener,
ImageRevealHelper.RevealStateListener {
private static final String TAG = ImageWallpaperRenderer.class.getSimpleName();
private final WallpaperManager mWallpaperManager;
private final ImageGLProgram mProgram;
private final ImageGLWallpaper mWallpaper;
private final ImageProcessHelper mImageProcessHelper;
private final ImageRevealHelper mImageRevealHelper;
private final ImageGLView mGLView;
private boolean mIsInAmbientMode;
private float mXOffset = 0f;
private float mYOffset = 0f;
public ImageWallpaperRenderer(Context context, ImageGLView glView) {
mWallpaperManager = context.getSystemService(WallpaperManager.class);
if (mWallpaperManager == null) {
Log.w(TAG, "WallpaperManager not available");
}
mProgram = new ImageGLProgram(context);
mWallpaper = new ImageGLWallpaper(mProgram);
mImageProcessHelper = new ImageProcessHelper();
mImageRevealHelper = new ImageRevealHelper(this);
mGLView = glView;
if (mWallpaperManager != null) {
// Compute per85 as transition threshold, this is an async work.
mImageProcessHelper.startComputingPercentile85(mWallpaperManager.getBitmap());
}
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
glClearColor(0f, 0f, 0f, 1.0f);
mProgram.useGLProgram(
R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader);
mWallpaper.setup();
mWallpaper.setupTexture(mWallpaperManager.getBitmap());
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
glViewport(0, 0, width, height);
mWallpaper.adjustTextureCoordinates(mWallpaperManager.getBitmap(),
width, height, mXOffset, mYOffset);
}
@Override
public void onDrawFrame(GL10 gl) {
float threshold = mImageProcessHelper.getPercentile85();
float reveal = mImageRevealHelper.getReveal();
glClear(GL_COLOR_BUFFER_BIT);
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_AOD2OPACITY), .25f);
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_CENTER_REVEAL), threshold);
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal);
glUniform1i(mWallpaper.getHandle(ImageGLWallpaper.U_AOD_MODE), mIsInAmbientMode ? 1 : 0);
mWallpaper.useTexture();
mWallpaper.draw();
}
@Override
public void onSensorEvent(boolean awake) {
mImageRevealHelper.updateAwake(awake);
}
@Override
public void onAmbientModeChanged(boolean inAmbientMode) {
mIsInAmbientMode = inAmbientMode;
if (inAmbientMode) {
mImageRevealHelper.sleep();
}
requestRender();
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset, Rect frame) {
if (frame == null || mWallpaperManager == null
|| (xOffset == mXOffset && yOffset == mYOffset)) {
return;
}
Bitmap bitmap = mWallpaperManager.getBitmap();
if (bitmap == null) {
return;
}
int width = frame.width();
int height = frame.height();
mXOffset = xOffset;
mYOffset = yOffset;
mWallpaper.adjustTextureCoordinates(bitmap, width, height, mXOffset, mYOffset);
requestRender();
}
@Override
public void onRevealStateChanged() {
requestRender();
}
private void requestRender() {
if (mGLView != null) {
mGLView.render();
}
}
}

View File

@@ -482,7 +482,8 @@ public class StatusBar extends SystemUI implements DemoMode,
updateAodMaskVisibility(deviceSupportsAodWallpaper && aodImageWallpaperEnabled);
// If WallpaperInfo is null, it must be ImageWallpaper.
final boolean supportsAmbientMode = deviceSupportsAodWallpaper
&& (info == null || info.supportsAmbientMode());
&& (info == null && aodImageWallpaperEnabled
|| info != null && info.supportsAmbientMode());
mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);

View File

@@ -156,8 +156,6 @@ public class AodMaskView extends ImageView implements StatusBarStateController.S
private boolean checkIfNeedMask() {
// We need mask for ImageWallpaper / LockScreen Wallpaper (Music album art).
// Because of conflicting with another wallpaper feature,
// we only support LockScreen wallpaper currently.
return mWallpaperManager.getWallpaperInfo() == null || ScrimState.AOD.hasBackdrop();
}