blob: e9ddb3831b1abc09aae699b9c02ae87e36e4088b [file] [log] [blame]
Ahan Wu67e7f102019-01-14 20:38:14 +08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.glwallpaper;
18
19import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
20import static android.opengl.GLES20.glClear;
21import static android.opengl.GLES20.glClearColor;
22import static android.opengl.GLES20.glUniform1f;
23import static android.opengl.GLES20.glViewport;
24
25import android.app.WallpaperManager;
26import android.content.Context;
Ahan Wu0e174802019-07-23 20:41:52 +080027import android.content.res.Configuration;
Ahan Wu67e7f102019-01-14 20:38:14 +080028import android.graphics.Bitmap;
29import android.graphics.Rect;
Ahan Wu67e7f102019-01-14 20:38:14 +080030import android.util.Log;
Ahan Wuc8363352019-03-07 17:35:27 +080031import android.util.MathUtils;
Ahan Wufa42c512019-05-15 19:52:51 +080032import android.util.Size;
Ahan Wue16e1fa2019-05-29 18:39:33 +080033import android.view.DisplayInfo;
Ahan Wu67e7f102019-01-14 20:38:14 +080034
Ahan Wu67e7f102019-01-14 20:38:14 +080035import com.android.systemui.R;
36
Ahan Wu76884242019-05-22 20:04:23 +080037import java.io.FileDescriptor;
38import java.io.PrintWriter;
Ahan Wu3222d3f2020-03-11 20:24:00 +080039import java.util.concurrent.atomic.AtomicInteger;
40import java.util.function.Consumer;
Ahan Wu76884242019-05-22 20:04:23 +080041
Ahan Wu67e7f102019-01-14 20:38:14 +080042/**
43 * A GL renderer for image wallpaper.
44 */
Ahan Wufa42c512019-05-15 19:52:51 +080045public class ImageWallpaperRenderer implements GLWallpaperRenderer,
46 ImageRevealHelper.RevealStateListener {
Ahan Wu67e7f102019-01-14 20:38:14 +080047 private static final String TAG = ImageWallpaperRenderer.class.getSimpleName();
Ahan Wue16e1fa2019-05-29 18:39:33 +080048 private static final float SCALE_VIEWPORT_MIN = 1f;
49 private static final float SCALE_VIEWPORT_MAX = 1.1f;
Ahan Wue88b1652019-09-19 22:12:46 +080050 private static final boolean DEBUG = true;
Ahan Wu67e7f102019-01-14 20:38:14 +080051
Ahan Wu67e7f102019-01-14 20:38:14 +080052 private final ImageGLProgram mProgram;
53 private final ImageGLWallpaper mWallpaper;
54 private final ImageProcessHelper mImageProcessHelper;
55 private final ImageRevealHelper mImageRevealHelper;
Ahan Wu67e7f102019-01-14 20:38:14 +080056
Ahan Wufa42c512019-05-15 19:52:51 +080057 private SurfaceProxy mProxy;
Ahan Wue16e1fa2019-05-29 18:39:33 +080058 private final Rect mScissor;
59 private final Rect mSurfaceSize = new Rect();
60 private final Rect mViewport = new Rect();
Ahan Wue16e1fa2019-05-29 18:39:33 +080061 private boolean mScissorMode;
62 private float mXOffset;
63 private float mYOffset;
Ahan Wu3222d3f2020-03-11 20:24:00 +080064 private final WallpaperTexture mTexture;
Ahan Wu48ebbd72019-03-12 20:59:13 +080065
Ahan Wufa42c512019-05-15 19:52:51 +080066 public ImageWallpaperRenderer(Context context, SurfaceProxy proxy) {
Ahan Wu3222d3f2020-03-11 20:24:00 +080067 final WallpaperManager wpm = context.getSystemService(WallpaperManager.class);
68 if (wpm == null) {
Ahan Wu67e7f102019-01-14 20:38:14 +080069 Log.w(TAG, "WallpaperManager not available");
70 }
71
Ahan Wu3222d3f2020-03-11 20:24:00 +080072 mTexture = new WallpaperTexture(wpm);
Ahan Wue16e1fa2019-05-29 18:39:33 +080073 DisplayInfo displayInfo = new DisplayInfo();
Ahan Wu4e404402020-01-27 20:39:57 +080074 context.getDisplay().getDisplayInfo(displayInfo);
Ahan Wu0e174802019-07-23 20:41:52 +080075
76 // We only do transition in portrait currently, b/137962047.
77 int orientation = context.getResources().getConfiguration().orientation;
78 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
79 mScissor = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
80 } else {
81 mScissor = new Rect(0, 0, displayInfo.logicalHeight, displayInfo.logicalWidth);
82 }
Ahan Wue16e1fa2019-05-29 18:39:33 +080083
Ahan Wufa42c512019-05-15 19:52:51 +080084 mProxy = proxy;
Ahan Wu67e7f102019-01-14 20:38:14 +080085 mProgram = new ImageGLProgram(context);
86 mWallpaper = new ImageGLWallpaper(mProgram);
87 mImageProcessHelper = new ImageProcessHelper();
88 mImageRevealHelper = new ImageRevealHelper(this);
Ahan Wu67e7f102019-01-14 20:38:14 +080089
Ahan Wu4e404402020-01-27 20:39:57 +080090 startProcessingImage();
91 }
92
93 protected void startProcessingImage() {
Ahan Wu3222d3f2020-03-11 20:24:00 +080094 // Compute threshold of the image, this is an async work.
95 mImageProcessHelper.start(mTexture);
Ahan Wu67e7f102019-01-14 20:38:14 +080096 }
97
98 @Override
Ahan Wu287d8282019-12-17 16:23:17 +080099 public boolean isWcgContent() {
Ahan Wu3222d3f2020-03-11 20:24:00 +0800100 return mTexture.isWcgContent();
Ahan Wu287d8282019-12-17 16:23:17 +0800101 }
102
103 @Override
Ahan Wufa42c512019-05-15 19:52:51 +0800104 public void onSurfaceCreated() {
Ahan Wu67e7f102019-01-14 20:38:14 +0800105 glClearColor(0f, 0f, 0f, 1.0f);
106 mProgram.useGLProgram(
107 R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader);
Ahan Wufa42c512019-05-15 19:52:51 +0800108
Ahan Wu3222d3f2020-03-11 20:24:00 +0800109 mTexture.use(bitmap -> {
110 if (bitmap == null) {
111 Log.w(TAG, "reload texture failed!");
Ahan Wufa42c512019-05-15 19:52:51 +0800112 }
Ahan Wu3222d3f2020-03-11 20:24:00 +0800113 mWallpaper.setup(bitmap);
114 });
Ahan Wu67e7f102019-01-14 20:38:14 +0800115 }
116
117 @Override
Ahan Wufa42c512019-05-15 19:52:51 +0800118 public void onSurfaceChanged(int width, int height) {
119 glViewport(0, 0, width, height);
120 }
121
122 @Override
123 public void onDrawFrame() {
Ahan Wu330bc602019-04-25 15:04:39 +0800124 float threshold = mImageProcessHelper.getThreshold();
Ahan Wu67e7f102019-01-14 20:38:14 +0800125 float reveal = mImageRevealHelper.getReveal();
126
Ahan Wu67e7f102019-01-14 20:38:14 +0800127 glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_AOD2OPACITY), 1);
Ahan Wu330bc602019-04-25 15:04:39 +0800128 glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_PER85), threshold);
Ahan Wu67e7f102019-01-14 20:38:14 +0800129 glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal);
130
Ahan Wue16e1fa2019-05-29 18:39:33 +0800131 glClear(GL_COLOR_BUFFER_BIT);
132 // We only need to scale viewport while doing transition.
133 if (mScissorMode) {
134 scaleViewport(reveal);
135 } else {
136 glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height());
137 }
Ahan Wu67e7f102019-01-14 20:38:14 +0800138 mWallpaper.useTexture();
139 mWallpaper.draw();
140 }
141
Ahan Wufa42c512019-05-15 19:52:51 +0800142 @Override
143 public void updateAmbientMode(boolean inAmbientMode, long duration) {
144 mImageRevealHelper.updateAwake(!inAmbientMode, duration);
145 }
146
147 @Override
Ahan Wue16e1fa2019-05-29 18:39:33 +0800148 public void updateOffsets(float xOffset, float yOffset) {
149 mXOffset = xOffset;
150 mYOffset = yOffset;
151 int left = (int) ((mSurfaceSize.width() - mScissor.width()) * xOffset);
152 int right = left + mScissor.width();
153 mScissor.set(left, mScissor.top, right, mScissor.bottom);
154 }
155
156 @Override
Ahan Wufa42c512019-05-15 19:52:51 +0800157 public Size reportSurfaceSize() {
Ahan Wu3222d3f2020-03-11 20:24:00 +0800158 mTexture.use(null);
159 mSurfaceSize.set(mTexture.getTextureDimensions());
Ahan Wufa42c512019-05-15 19:52:51 +0800160 return new Size(mSurfaceSize.width(), mSurfaceSize.height());
161 }
162
163 @Override
164 public void finish() {
165 mProxy = null;
166 }
167
Ahan Wuc8363352019-03-07 17:35:27 +0800168 private void scaleViewport(float reveal) {
Ahan Wue16e1fa2019-05-29 18:39:33 +0800169 int left = mScissor.left;
170 int top = mScissor.top;
171 int width = mScissor.width();
172 int height = mScissor.height();
Ahan Wuc8363352019-03-07 17:35:27 +0800173 // Interpolation between SCALE_VIEWPORT_MAX and SCALE_VIEWPORT_MIN by reveal.
Ahan Wue16e1fa2019-05-29 18:39:33 +0800174 float vpScaled = MathUtils.lerp(SCALE_VIEWPORT_MIN, SCALE_VIEWPORT_MAX, reveal);
Ahan Wuc8363352019-03-07 17:35:27 +0800175 // Calculate the offset amount from the lower left corner.
Ahan Wue16e1fa2019-05-29 18:39:33 +0800176 float offset = (SCALE_VIEWPORT_MIN - vpScaled) / 2;
Ahan Wuc8363352019-03-07 17:35:27 +0800177 // Change the viewport.
Ahan Wue16e1fa2019-05-29 18:39:33 +0800178 mViewport.set((int) (left + width * offset), (int) (top + height * offset),
Ahan Wufa42c512019-05-15 19:52:51 +0800179 (int) (width * vpScaled), (int) (height * vpScaled));
Ahan Wue16e1fa2019-05-29 18:39:33 +0800180 glViewport(mViewport.left, mViewport.top, mViewport.right, mViewport.bottom);
Ahan Wu67e7f102019-01-14 20:38:14 +0800181 }
182
183 @Override
184 public void onRevealStateChanged() {
Ahan Wufa42c512019-05-15 19:52:51 +0800185 mProxy.requestRender();
Ahan Wu67e7f102019-01-14 20:38:14 +0800186 }
187
Ahan Wufa42c512019-05-15 19:52:51 +0800188 @Override
Ahan Wu0e174802019-07-23 20:41:52 +0800189 public void onRevealStart(boolean animate) {
190 if (animate) {
191 mScissorMode = true;
192 // Use current display area of texture.
193 mWallpaper.adjustTextureCoordinates(mSurfaceSize, mScissor, mXOffset, mYOffset);
194 }
Ahan Wufa42c512019-05-15 19:52:51 +0800195 mProxy.preRender();
196 }
197
198 @Override
199 public void onRevealEnd() {
Ahan Wu0e174802019-07-23 20:41:52 +0800200 if (mScissorMode) {
201 mScissorMode = false;
202 // reset texture coordinates to use full texture.
203 mWallpaper.adjustTextureCoordinates(null, null, 0, 0);
204 // We need draw full texture back before finishing render.
205 mProxy.requestRender();
206 }
Ahan Wufa42c512019-05-15 19:52:51 +0800207 mProxy.postRender();
Ahan Wu67e7f102019-01-14 20:38:14 +0800208 }
Ahan Wu76884242019-05-22 20:04:23 +0800209
210 @Override
211 public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
212 out.print(prefix); out.print("mProxy="); out.print(mProxy);
213 out.print(prefix); out.print("mSurfaceSize="); out.print(mSurfaceSize);
Ahan Wue16e1fa2019-05-29 18:39:33 +0800214 out.print(prefix); out.print("mScissor="); out.print(mScissor);
215 out.print(prefix); out.print("mViewport="); out.print(mViewport);
216 out.print(prefix); out.print("mScissorMode="); out.print(mScissorMode);
217 out.print(prefix); out.print("mXOffset="); out.print(mXOffset);
218 out.print(prefix); out.print("mYOffset="); out.print(mYOffset);
Ahan Wu76884242019-05-22 20:04:23 +0800219 out.print(prefix); out.print("threshold="); out.print(mImageProcessHelper.getThreshold());
Ahan Wue88b1652019-09-19 22:12:46 +0800220 out.print(prefix); out.print("mReveal="); out.print(mImageRevealHelper.getReveal());
Ahan Wu3222d3f2020-03-11 20:24:00 +0800221 out.print(prefix); out.print("mWcgContent="); out.print(isWcgContent());
Ahan Wue16e1fa2019-05-29 18:39:33 +0800222 mWallpaper.dump(prefix, fd, out, args);
Ahan Wu76884242019-05-22 20:04:23 +0800223 }
Ahan Wu3222d3f2020-03-11 20:24:00 +0800224
225 static class WallpaperTexture {
226 private final AtomicInteger mRefCount;
227 private final Rect mDimensions;
228 private final WallpaperManager mWallpaperManager;
229 private Bitmap mBitmap;
230 private boolean mWcgContent;
231
232 private WallpaperTexture(WallpaperManager wallpaperManager) {
233 mWallpaperManager = wallpaperManager;
234 mRefCount = new AtomicInteger();
235 mDimensions = new Rect();
236 }
237
238 public void use(Consumer<Bitmap> consumer) {
239 mRefCount.incrementAndGet();
240 synchronized (mRefCount) {
241 if (mBitmap == null) {
242 mBitmap = mWallpaperManager.getBitmap(false /* hardware */);
243 mWcgContent = mWallpaperManager.wallpaperSupportsWcg(
244 WallpaperManager.FLAG_SYSTEM);
245 mWallpaperManager.forgetLoadedWallpaper();
246 if (mBitmap != null) {
247 mDimensions.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
248 } else {
249 Log.w(TAG, "Can't get bitmap");
250 }
251 }
252 }
253 if (consumer != null) {
254 consumer.accept(mBitmap);
255 }
256 synchronized (mRefCount) {
257 final int count = mRefCount.decrementAndGet();
258 if (count == 0 && mBitmap != null) {
259 if (DEBUG) {
260 Log.v(TAG, "WallpaperTexture: release 0x" + getHash()
261 + ", refCount=" + count);
262 }
263 mBitmap.recycle();
264 mBitmap = null;
265 }
266 }
267 }
268
269 private boolean isWcgContent() {
270 return mWcgContent;
271 }
272
273 private String getHash() {
274 return mBitmap != null ? Integer.toHexString(mBitmap.hashCode()) : "null";
275 }
276
277 private Rect getTextureDimensions() {
278 return mDimensions;
279 }
280
281 @Override
282 public String toString() {
283 return "{" + getHash() + ", " + mRefCount.get() + "}";
284 }
285 }
Ahan Wu67e7f102019-01-14 20:38:14 +0800286}