Revert "Render ImageWallpaper with OpenGL ES and apply visual effects."
This reverts commit 9a8e260af1.
Bug: 118658627
Reason for revert:
I've received a few bug reports indicating that images were getting stretched, animations were gone and sometimes nothing would be rendered.
I'll revert the CL to have something for stable for Beta 1. We can then work on the fixes after the Taiwan team is back from vacation.
Change-Id: Id09ba3d7f372af9153c056a12e676c0227d19939
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
attribute vec4 aPosition;
|
||||
attribute vec2 aTextureCoordinates;
|
||||
varying vec2 vTextureCoordinates;
|
||||
|
||||
void main() {
|
||||
vTextureCoordinates = aTextureCoordinates;
|
||||
gl_Position = aPosition;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,7 +480,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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -2221,9 +2221,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
|
||||
synchronized (mLock) {
|
||||
mInAmbientMode = inAmbientMode;
|
||||
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
|
||||
final boolean hasConnection = data != null && data.connection != null;
|
||||
final WallpaperInfo info = hasConnection ? data.connection.mInfo : null;
|
||||
|
||||
// The wallpaper info is null for image wallpaper, also use the engine in this case.
|
||||
if (data != null && data.connection != null && (data.connection.mInfo == null
|
||||
|| data.connection.mInfo.supportsAmbientMode())) {
|
||||
if (hasConnection && (info == null && isAodImageWallpaperEnabled()
|
||||
|| info != null && info.supportsAmbientMode())) {
|
||||
// TODO(multi-display) Extends this method with specific display.
|
||||
engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user