1 /*
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 
17 package com.android.systemui.glwallpaper;
18 
19 import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
20 import static android.opengl.GLES20.glClear;
21 import static android.opengl.GLES20.glClearColor;
22 import static android.opengl.GLES20.glViewport;
23 
24 import android.app.WallpaperManager;
25 import android.content.Context;
26 import android.graphics.Bitmap;
27 import android.graphics.Rect;
28 import android.util.Log;
29 import android.util.Size;
30 
31 import com.android.systemui.R;
32 
33 import java.io.FileDescriptor;
34 import java.io.PrintWriter;
35 import java.util.concurrent.atomic.AtomicInteger;
36 import java.util.function.Consumer;
37 
38 /**
39  * A GL renderer for image wallpaper.
40  */
41 public class ImageWallpaperRenderer implements GLWallpaperRenderer {
42     private static final String TAG = ImageWallpaperRenderer.class.getSimpleName();
43     private static final boolean DEBUG = false;
44 
45     private final ImageGLProgram mProgram;
46     private final ImageGLWallpaper mWallpaper;
47     private final Rect mSurfaceSize = new Rect();
48     private final WallpaperTexture mTexture;
49 
ImageWallpaperRenderer(Context context)50     public ImageWallpaperRenderer(Context context) {
51         final WallpaperManager wpm = context.getSystemService(WallpaperManager.class);
52         if (wpm == null) {
53             Log.w(TAG, "WallpaperManager not available");
54         }
55 
56         mTexture = new WallpaperTexture(wpm);
57         mProgram = new ImageGLProgram(context);
58         mWallpaper = new ImageGLWallpaper(mProgram);
59     }
60 
61     @Override
isWcgContent()62     public boolean isWcgContent() {
63         return mTexture.isWcgContent();
64     }
65 
66     @Override
onSurfaceCreated()67     public void onSurfaceCreated() {
68         glClearColor(0f, 0f, 0f, 1.0f);
69         mProgram.useGLProgram(
70                 R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader);
71 
72         mTexture.use(bitmap -> {
73             if (bitmap == null) {
74                 Log.w(TAG, "reload texture failed!");
75             }
76             mWallpaper.setup(bitmap);
77         });
78     }
79 
80     @Override
onSurfaceChanged(int width, int height)81     public void onSurfaceChanged(int width, int height) {
82         glViewport(0, 0, width, height);
83     }
84 
85     @Override
onDrawFrame()86     public void onDrawFrame() {
87         glClear(GL_COLOR_BUFFER_BIT);
88         glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height());
89         mWallpaper.useTexture();
90         mWallpaper.draw();
91     }
92 
93     @Override
reportSurfaceSize()94     public Size reportSurfaceSize() {
95         mTexture.use(null /* consumer */);
96         mSurfaceSize.set(mTexture.getTextureDimensions());
97         return new Size(mSurfaceSize.width(), mSurfaceSize.height());
98     }
99 
100     @Override
finish()101     public void finish() {
102     }
103 
104     @Override
dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args)105     public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
106         out.print(prefix); out.print("mSurfaceSize="); out.print(mSurfaceSize);
107         out.print(prefix); out.print("mWcgContent="); out.print(isWcgContent());
108         mWallpaper.dump(prefix, fd, out, args);
109     }
110 
111     static class WallpaperTexture {
112         private final AtomicInteger mRefCount;
113         private final Rect mDimensions;
114         private final WallpaperManager mWallpaperManager;
115         private Bitmap mBitmap;
116         private boolean mWcgContent;
117 
WallpaperTexture(WallpaperManager wallpaperManager)118         private WallpaperTexture(WallpaperManager wallpaperManager) {
119             mWallpaperManager = wallpaperManager;
120             mRefCount = new AtomicInteger();
121             mDimensions = new Rect();
122         }
123 
use(Consumer<Bitmap> consumer)124         public void use(Consumer<Bitmap> consumer) {
125             mRefCount.incrementAndGet();
126             synchronized (mRefCount) {
127                 if (mBitmap == null) {
128                     mBitmap = mWallpaperManager.getBitmap(false /* hardware */);
129                     mWcgContent = mWallpaperManager.wallpaperSupportsWcg(
130                             WallpaperManager.FLAG_SYSTEM);
131                     mWallpaperManager.forgetLoadedWallpaper();
132                     if (mBitmap != null) {
133                         mDimensions.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
134                     } else {
135                         Log.w(TAG, "Can't get bitmap");
136                     }
137                 }
138             }
139             if (consumer != null) {
140                 consumer.accept(mBitmap);
141             }
142             synchronized (mRefCount) {
143                 final int count = mRefCount.decrementAndGet();
144                 if (count == 0 && mBitmap != null) {
145                     if (DEBUG) {
146                         Log.v(TAG, "WallpaperTexture: release 0x" + getHash()
147                                 + ", refCount=" + count);
148                     }
149                     mBitmap.recycle();
150                     mBitmap = null;
151                 }
152             }
153         }
154 
isWcgContent()155         private boolean isWcgContent() {
156             return mWcgContent;
157         }
158 
getHash()159         private String getHash() {
160             return mBitmap != null ? Integer.toHexString(mBitmap.hashCode()) : "null";
161         }
162 
getTextureDimensions()163         private Rect getTextureDimensions() {
164             return mDimensions;
165         }
166 
167         @Override
toString()168         public String toString() {
169             return "{" + getHash() + ", " + mRefCount.get() + "}";
170         }
171     }
172 }
173