blob: 71ec33e16e0e7cc81ead3dd7ac25a39e9e9cd5b4 [file] [log] [blame]
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001/*
2 * Copyright (C) 2009 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
Dianne Hackbornba398392011-08-01 16:11:57 -070017package com.android.systemui;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070018
Dianne Hackborn759a39e2009-08-09 17:20:27 -070019import android.graphics.Rect;
Beverlyf8f2f162020-02-25 13:47:45 -050020import android.os.Handler;
Ahan Wu44ab58a2019-06-20 18:14:29 +080021import android.os.HandlerThread;
Beverlyf8f2f162020-02-25 13:47:45 -050022import android.os.SystemClock;
Ahan Wue88b1652019-09-19 22:12:46 +080023import android.os.Trace;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070024import android.service.wallpaper.WallpaperService;
Ahan Wufa42c512019-05-15 19:52:51 +080025import android.util.Log;
26import android.util.Size;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070027import android.view.SurfaceHolder;
Romain Guy407ec782011-08-24 17:06:58 -070028
Ahan Wufa42c512019-05-15 19:52:51 +080029import com.android.internal.annotations.VisibleForTesting;
30import com.android.systemui.glwallpaper.EglHelper;
31import com.android.systemui.glwallpaper.GLWallpaperRenderer;
Ahan Wu67e7f102019-01-14 20:38:14 +080032import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
Valentin Iftime6239e532018-08-24 17:17:26 +020033
Ahan Wu76884242019-05-22 20:04:23 +080034import java.io.FileDescriptor;
35import java.io.PrintWriter;
36
Dave Mankoff2aff6c32019-10-14 17:40:37 -040037import javax.inject.Inject;
38
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070039/**
40 * Default built-in wallpaper that simply shows a static image.
41 */
Romain Guy407ec782011-08-24 17:06:58 -070042@SuppressWarnings({"UnusedDeclaration"})
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070043public class ImageWallpaper extends WallpaperService {
Ahan Wub4924522019-02-20 19:15:04 +080044 private static final String TAG = ImageWallpaper.class.getSimpleName();
Ahan Wufa42c512019-05-15 19:52:51 +080045 // We delayed destroy render context that subsequent render requests have chance to cancel it.
46 // This is to avoid destroying then recreating render context in a very short time.
47 private static final int DELAY_FINISH_RENDERING = 1000;
Ahan Wu4a297792020-04-16 03:00:14 +080048 private static final boolean DEBUG = false;
Ahan Wu44ab58a2019-06-20 18:14:29 +080049 private HandlerThread mWorker;
50
Dave Mankoff2aff6c32019-10-14 17:40:37 -040051 @Inject
Ahan Wu4a297792020-04-16 03:00:14 +080052 public ImageWallpaper() {
Dave Mankoff2aff6c32019-10-14 17:40:37 -040053 super();
Dave Mankoff2aff6c32019-10-14 17:40:37 -040054 }
55
Ahan Wu44ab58a2019-06-20 18:14:29 +080056 @Override
57 public void onCreate() {
58 super.onCreate();
59 mWorker = new HandlerThread(TAG);
60 mWorker.start();
61 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -070062
Romain Guyef654bd2009-08-11 19:12:17 -070063 @Override
Romain Guyef654bd2009-08-11 19:12:17 -070064 public Engine onCreateEngine() {
Ahan Wu4a297792020-04-16 03:00:14 +080065 return new GLEngine();
Romain Guyef654bd2009-08-11 19:12:17 -070066 }
67
Ahan Wu44ab58a2019-06-20 18:14:29 +080068 @Override
69 public void onDestroy() {
70 super.onDestroy();
71 mWorker.quitSafely();
72 mWorker = null;
73 }
74
Ahan Wu4a297792020-04-16 03:00:14 +080075 class GLEngine extends Engine {
Ahan Wufa42c512019-05-15 19:52:51 +080076 // Surface is rejected if size below a threshold on some devices (ie. 8px on elfin)
77 // set min to 64 px (CTS covers this), please refer to ag/4867989 for detail.
78 @VisibleForTesting
79 static final int MIN_SURFACE_WIDTH = 64;
80 @VisibleForTesting
81 static final int MIN_SURFACE_HEIGHT = 64;
82
83 private GLWallpaperRenderer mRenderer;
84 private EglHelper mEglHelper;
Ahan Wufa42c512019-05-15 19:52:51 +080085 private final Runnable mFinishRenderingTask = this::finishRendering;
Ahan Wufa42c512019-05-15 19:52:51 +080086 private boolean mNeedRedraw;
Ahan Wu67e7f102019-01-14 20:38:14 +080087
Ahan Wu4a297792020-04-16 03:00:14 +080088 GLEngine() {
Beverlyf8f2f162020-02-25 13:47:45 -050089 }
90
91 @VisibleForTesting
Ahan Wu4a297792020-04-16 03:00:14 +080092 GLEngine(Handler handler) {
Beverlyf8f2f162020-02-25 13:47:45 -050093 super(SystemClock::elapsedRealtime, handler);
Ahan Wufa42c512019-05-15 19:52:51 +080094 }
95
96 @Override
97 public void onCreate(SurfaceHolder surfaceHolder) {
Ahan Wu4e404402020-01-27 20:39:57 +080098 mEglHelper = getEglHelperInstance();
Ahan Wu287d8282019-12-17 16:23:17 +080099 // Deferred init renderer because we need to get wallpaper by display context.
Ahan Wu4e404402020-01-27 20:39:57 +0800100 mRenderer = getRendererInstance();
Ahan Wufa42c512019-05-15 19:52:51 +0800101 setFixedSizeAllowed(true);
Ahan Wu4a297792020-04-16 03:00:14 +0800102 setOffsetNotificationsEnabled(false);
Ahan Wufa42c512019-05-15 19:52:51 +0800103 updateSurfaceSize();
104 }
105
Ahan Wu4e404402020-01-27 20:39:57 +0800106 EglHelper getEglHelperInstance() {
107 return new EglHelper();
108 }
109
110 ImageWallpaperRenderer getRendererInstance() {
Ahan Wu4a297792020-04-16 03:00:14 +0800111 return new ImageWallpaperRenderer(getDisplayContext());
Ahan Wu4e404402020-01-27 20:39:57 +0800112 }
113
Ahan Wufa42c512019-05-15 19:52:51 +0800114 private void updateSurfaceSize() {
115 SurfaceHolder holder = getSurfaceHolder();
116 Size frameSize = mRenderer.reportSurfaceSize();
117 int width = Math.max(MIN_SURFACE_WIDTH, frameSize.getWidth());
118 int height = Math.max(MIN_SURFACE_HEIGHT, frameSize.getHeight());
119 holder.setFixedSize(width, height);
Ahan Wu67e7f102019-01-14 20:38:14 +0800120 }
121
Lucas Dupin13f4b8a2020-02-19 13:41:52 -0800122 @Override
123 public boolean shouldZoomOutWallpaper() {
124 return true;
125 }
126
Ahan Wu48ebbd72019-03-12 20:59:13 +0800127 @Override
128 public void onDestroy() {
Ahan Wu44ab58a2019-06-20 18:14:29 +0800129 mWorker.getThreadHandler().post(() -> {
130 mRenderer.finish();
131 mRenderer = null;
132 mEglHelper.finish();
133 mEglHelper = null;
Ahan Wu44ab58a2019-06-20 18:14:29 +0800134 });
Ahan Wu48ebbd72019-03-12 20:59:13 +0800135 }
136
Ahan Wufa42c512019-05-15 19:52:51 +0800137 @Override
138 public void onSurfaceCreated(SurfaceHolder holder) {
Ahan Wuc9c7ebb2020-02-17 18:49:59 +0800139 if (mWorker == null) return;
Ahan Wu44ab58a2019-06-20 18:14:29 +0800140 mWorker.getThreadHandler().post(() -> {
Ahan Wu287d8282019-12-17 16:23:17 +0800141 mEglHelper.init(holder, needSupportWideColorGamut());
Ahan Wu44ab58a2019-06-20 18:14:29 +0800142 mRenderer.onSurfaceCreated();
143 });
Ahan Wufa42c512019-05-15 19:52:51 +0800144 }
Ahan Wu67e7f102019-01-14 20:38:14 +0800145
Ahan Wufa42c512019-05-15 19:52:51 +0800146 @Override
147 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Ahan Wuc9c7ebb2020-02-17 18:49:59 +0800148 if (mWorker == null) return;
Ahan Wu4a297792020-04-16 03:00:14 +0800149 mWorker.getThreadHandler().post(() -> mRenderer.onSurfaceChanged(width, height));
Ahan Wufa42c512019-05-15 19:52:51 +0800150 }
Ahan Wu67e7f102019-01-14 20:38:14 +0800151
Ahan Wufa42c512019-05-15 19:52:51 +0800152 @Override
153 public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
Ahan Wuc9c7ebb2020-02-17 18:49:59 +0800154 if (mWorker == null) return;
Ahan Wu4a297792020-04-16 03:00:14 +0800155 mWorker.getThreadHandler().post(this::drawFrame);
Ahan Wue88b1652019-09-19 22:12:46 +0800156 }
157
158 private void drawFrame() {
159 preRender();
160 requestRender();
161 postRender();
162 }
163
Ahan Wufa42c512019-05-15 19:52:51 +0800164 public void preRender() {
Ahan Wub3780592019-07-04 20:50:00 +0800165 // This method should only be invoked from worker thread.
Ahan Wue88b1652019-09-19 22:12:46 +0800166 Trace.beginSection("ImageWallpaper#preRender");
Ahan Wub3780592019-07-04 20:50:00 +0800167 preRenderInternal();
Ahan Wue88b1652019-09-19 22:12:46 +0800168 Trace.endSection();
Ahan Wu44ab58a2019-06-20 18:14:29 +0800169 }
170
171 private void preRenderInternal() {
Ahan Wufa42c512019-05-15 19:52:51 +0800172 boolean contextRecreated = false;
173 Rect frame = getSurfaceHolder().getSurfaceFrame();
Ahan Wu44ab58a2019-06-20 18:14:29 +0800174 cancelFinishRenderingTask();
Ahan Wu67e7f102019-01-14 20:38:14 +0800175
Ahan Wufa42c512019-05-15 19:52:51 +0800176 // Check if we need to recreate egl context.
177 if (!mEglHelper.hasEglContext()) {
178 mEglHelper.destroyEglSurface();
179 if (!mEglHelper.createEglContext()) {
180 Log.w(TAG, "recreate egl context failed!");
181 } else {
182 contextRecreated = true;
183 }
184 }
Ahan Wu67e7f102019-01-14 20:38:14 +0800185
Ahan Wufa42c512019-05-15 19:52:51 +0800186 // Check if we need to recreate egl surface.
187 if (mEglHelper.hasEglContext() && !mEglHelper.hasEglSurface()) {
Ahan Wu287d8282019-12-17 16:23:17 +0800188 if (!mEglHelper.createEglSurface(getSurfaceHolder(), needSupportWideColorGamut())) {
Ahan Wufa42c512019-05-15 19:52:51 +0800189 Log.w(TAG, "recreate egl surface failed!");
190 }
191 }
192
193 // If we recreate egl context, notify renderer to setup again.
194 if (mEglHelper.hasEglContext() && mEglHelper.hasEglSurface() && contextRecreated) {
195 mRenderer.onSurfaceCreated();
196 mRenderer.onSurfaceChanged(frame.width(), frame.height());
197 }
198 }
199
Ahan Wufa42c512019-05-15 19:52:51 +0800200 public void requestRender() {
Ahan Wub3780592019-07-04 20:50:00 +0800201 // This method should only be invoked from worker thread.
Ahan Wue88b1652019-09-19 22:12:46 +0800202 Trace.beginSection("ImageWallpaper#requestRender");
Ahan Wub3780592019-07-04 20:50:00 +0800203 requestRenderInternal();
Ahan Wue88b1652019-09-19 22:12:46 +0800204 Trace.endSection();
Ahan Wu44ab58a2019-06-20 18:14:29 +0800205 }
206
207 private void requestRenderInternal() {
Ahan Wufa42c512019-05-15 19:52:51 +0800208 Rect frame = getSurfaceHolder().getSurfaceFrame();
209 boolean readyToRender = mEglHelper.hasEglContext() && mEglHelper.hasEglSurface()
210 && frame.width() > 0 && frame.height() > 0;
211
212 if (readyToRender) {
213 mRenderer.onDrawFrame();
214 if (!mEglHelper.swapBuffer()) {
215 Log.e(TAG, "drawFrame failed!");
216 }
217 } else {
218 Log.e(TAG, "requestRender: not ready, has context=" + mEglHelper.hasEglContext()
219 + ", has surface=" + mEglHelper.hasEglSurface()
220 + ", frame=" + frame);
221 }
222 }
223
Ahan Wufa42c512019-05-15 19:52:51 +0800224 public void postRender() {
Ahan Wub3780592019-07-04 20:50:00 +0800225 // This method should only be invoked from worker thread.
Ahan Wue88b1652019-09-19 22:12:46 +0800226 Trace.beginSection("ImageWallpaper#postRender");
Ahan Wub3780592019-07-04 20:50:00 +0800227 scheduleFinishRendering();
Ahan Wue88b1652019-09-19 22:12:46 +0800228 Trace.endSection();
Ahan Wub3780592019-07-04 20:50:00 +0800229 }
230
Ahan Wu44ab58a2019-06-20 18:14:29 +0800231 private void cancelFinishRenderingTask() {
Ahan Wuc9c7ebb2020-02-17 18:49:59 +0800232 if (mWorker == null) return;
Ahan Wu44ab58a2019-06-20 18:14:29 +0800233 mWorker.getThreadHandler().removeCallbacks(mFinishRenderingTask);
Ahan Wufa42c512019-05-15 19:52:51 +0800234 }
235
236 private void scheduleFinishRendering() {
Ahan Wuc9c7ebb2020-02-17 18:49:59 +0800237 if (mWorker == null) return;
Ahan Wu44ab58a2019-06-20 18:14:29 +0800238 cancelFinishRenderingTask();
239 mWorker.getThreadHandler().postDelayed(mFinishRenderingTask, DELAY_FINISH_RENDERING);
Ahan Wufa42c512019-05-15 19:52:51 +0800240 }
241
242 private void finishRendering() {
Ahan Wue88b1652019-09-19 22:12:46 +0800243 Trace.beginSection("ImageWallpaper#finishRendering");
Ahan Wufa42c512019-05-15 19:52:51 +0800244 if (mEglHelper != null) {
245 mEglHelper.destroyEglSurface();
Ahan Wu4a297792020-04-16 03:00:14 +0800246 mEglHelper.destroyEglContext();
Ahan Wufa42c512019-05-15 19:52:51 +0800247 }
Ahan Wue88b1652019-09-19 22:12:46 +0800248 Trace.endSection();
Ahan Wufa42c512019-05-15 19:52:51 +0800249 }
250
Ahan Wu287d8282019-12-17 16:23:17 +0800251 private boolean needSupportWideColorGamut() {
252 return mRenderer.isWcgContent();
253 }
254
Ahan Wu76884242019-05-22 20:04:23 +0800255 @Override
256 protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
257 super.dump(prefix, fd, out, args);
258 out.print(prefix); out.print("Engine="); out.println(this);
Ahan Wu76884242019-05-22 20:04:23 +0800259 out.print(prefix); out.print("valid surface=");
260 out.println(getSurfaceHolder() != null && getSurfaceHolder().getSurface() != null
261 ? getSurfaceHolder().getSurface().isValid()
262 : "null");
263
264 out.print(prefix); out.print("surface frame=");
265 out.println(getSurfaceHolder() != null ? getSurfaceHolder().getSurfaceFrame() : "null");
266
267 mEglHelper.dump(prefix, fd, out, args);
268 mRenderer.dump(prefix, fd, out, args);
269 }
Ahan Wu67e7f102019-01-14 20:38:14 +0800270 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700271}