/* * 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.glViewport; import android.app.WallpaperManager; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Rect; import android.util.Log; import android.util.Size; import com.android.systemui.R; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; /** * A GL renderer for image wallpaper. */ public class ImageWallpaperRenderer implements GLWallpaperRenderer { private static final String TAG = ImageWallpaperRenderer.class.getSimpleName(); private static final boolean DEBUG = false; private final ImageGLProgram mProgram; private final ImageGLWallpaper mWallpaper; private final Rect mSurfaceSize = new Rect(); private final WallpaperTexture mTexture; public ImageWallpaperRenderer(Context context) { final WallpaperManager wpm = context.getSystemService(WallpaperManager.class); if (wpm == null) { Log.w(TAG, "WallpaperManager not available"); } mTexture = new WallpaperTexture(wpm); mProgram = new ImageGLProgram(context); mWallpaper = new ImageGLWallpaper(mProgram); } @Override public boolean isWcgContent() { return mTexture.isWcgContent(); } @Override public void onSurfaceCreated() { glClearColor(0f, 0f, 0f, 1.0f); mProgram.useGLProgram( R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader); mTexture.use(bitmap -> { if (bitmap == null) { Log.w(TAG, "reload texture failed!"); } mWallpaper.setup(bitmap); }); } @Override public void onSurfaceChanged(int width, int height) { glViewport(0, 0, width, height); } @Override public void onDrawFrame() { glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height()); mWallpaper.useTexture(); mWallpaper.draw(); } @Override public Size reportSurfaceSize() { mTexture.use(null /* consumer */); mSurfaceSize.set(mTexture.getTextureDimensions()); return new Size(mSurfaceSize.width(), mSurfaceSize.height()); } @Override public void finish() { } @Override public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) { out.print(prefix); out.print("mSurfaceSize="); out.print(mSurfaceSize); out.print(prefix); out.print("mWcgContent="); out.print(isWcgContent()); mWallpaper.dump(prefix, fd, out, args); } static class WallpaperTexture { private final AtomicInteger mRefCount; private final Rect mDimensions; private final WallpaperManager mWallpaperManager; private Bitmap mBitmap; private boolean mWcgContent; private WallpaperTexture(WallpaperManager wallpaperManager) { mWallpaperManager = wallpaperManager; mRefCount = new AtomicInteger(); mDimensions = new Rect(); } public void use(Consumer consumer) { mRefCount.incrementAndGet(); synchronized (mRefCount) { if (mBitmap == null) { mBitmap = mWallpaperManager.getBitmap(false /* hardware */); mWcgContent = mWallpaperManager.wallpaperSupportsWcg( WallpaperManager.FLAG_SYSTEM); mWallpaperManager.forgetLoadedWallpaper(); if (mBitmap != null) { mDimensions.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); } else { Log.w(TAG, "Can't get bitmap"); } } } if (consumer != null) { consumer.accept(mBitmap); } synchronized (mRefCount) { final int count = mRefCount.decrementAndGet(); if (count == 0 && mBitmap != null) { if (DEBUG) { Log.v(TAG, "WallpaperTexture: release 0x" + getHash() + ", refCount=" + count); } mBitmap.recycle(); mBitmap = null; } } } private boolean isWcgContent() { return mWcgContent; } private String getHash() { return mBitmap != null ? Integer.toHexString(mBitmap.hashCode()) : "null"; } private Rect getTextureDimensions() { return mDimensions; } @Override public String toString() { return "{" + getHash() + ", " + mRefCount.get() + "}"; } } }