Loading packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +150 −70 Original line number Diff line number Diff line Loading @@ -16,13 +16,22 @@ package com.android.systemui; import android.app.ActivityManager; import android.content.Context; import android.graphics.Rect; import android.opengl.GLSurfaceView; import android.service.wallpaper.WallpaperService; import android.util.Log; import android.util.Size; import android.view.SurfaceHolder; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.glwallpaper.EglHelper; import com.android.systemui.glwallpaper.GLWallpaperRenderer; import com.android.systemui.glwallpaper.ImageWallpaperRenderer; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.DozeParameters; /** * Default built-in wallpaper that simply shows a static image. Loading @@ -30,51 +39,98 @@ import com.android.systemui.glwallpaper.ImageWallpaperRenderer; @SuppressWarnings({"UnusedDeclaration"}) public class ImageWallpaper extends WallpaperService { private static final String TAG = ImageWallpaper.class.getSimpleName(); // We delayed destroy render context that subsequent render requests have chance to cancel it. // This is to avoid destroying then recreating render context in a very short time. private static final int DELAY_FINISH_RENDERING = 1000; @Override public Engine onCreateEngine() { return new GLEngine(this); } class GLEngine extends Engine { private GLWallpaperSurfaceView mWallpaperSurfaceView; class GLEngine extends Engine implements GLWallpaperRenderer.SurfaceProxy, StateListener { // Surface is rejected if size below a threshold on some devices (ie. 8px on elfin) // set min to 64 px (CTS covers this), please refer to ag/4867989 for detail. @VisibleForTesting static final int MIN_SURFACE_WIDTH = 64; @VisibleForTesting static final int MIN_SURFACE_HEIGHT = 64; private GLWallpaperRenderer mRenderer; private EglHelper mEglHelper; private StatusBarStateController mController; private final Runnable mFinishRenderingTask = this::finishRendering; private final boolean mNeedTransition; private boolean mNeedRedraw; GLEngine(Context context) { mWallpaperSurfaceView = new GLWallpaperSurfaceView(context); mWallpaperSurfaceView.setRenderer( new ImageWallpaperRenderer(context, mWallpaperSurfaceView)); mWallpaperSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); setOffsetNotificationsEnabled(true); mNeedTransition = ActivityManager.isHighEndGfx() && !DozeParameters.getInstance(context).getDisplayNeedsBlanking(); // We will preserve EGL context when we are in lock screen or aod // to avoid janking in following transition, we need to release when back to home. mController = Dependency.get(StatusBarStateController.class); if (mController != null) { mController.addCallback(this /* StateListener */); } mEglHelper = new EglHelper(); mRenderer = new ImageWallpaperRenderer(context, this /* SurfaceProxy */); } @Override public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { if (mWallpaperSurfaceView != null) { mWallpaperSurfaceView.notifyAmbientModeChanged(inAmbientMode, animationDuration); public void onCreate(SurfaceHolder surfaceHolder) { setFixedSizeAllowed(true); setOffsetNotificationsEnabled(false); updateSurfaceSize(); } private void updateSurfaceSize() { SurfaceHolder holder = getSurfaceHolder(); Size frameSize = mRenderer.reportSurfaceSize(); int width = Math.max(MIN_SURFACE_WIDTH, frameSize.getWidth()); int height = Math.max(MIN_SURFACE_HEIGHT, frameSize.getHeight()); holder.setFixedSize(width, height); } @Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { if (mWallpaperSurfaceView != null) { mWallpaperSurfaceView.notifyOffsetsChanged(xOffset, yOffset); } public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { mRenderer.updateAmbientMode(inAmbientMode, (mNeedTransition || animationDuration != 0) ? animationDuration : 0); } @Override public void onDestroy() { if (mWallpaperSurfaceView != null) { mWallpaperSurfaceView.onPause(); if (mController != null) { mController.removeCallback(this /* StateListener */); } mController = null; mRenderer.finish(); mRenderer = null; mEglHelper.finish(); mEglHelper = null; getSurfaceHolder().getSurface().hwuiDestroy(); } @Override public void onSurfaceCreated(SurfaceHolder holder) { mEglHelper.init(holder); mRenderer.onSurfaceCreated(); } private class GLWallpaperSurfaceView extends GLSurfaceView implements ImageGLView { private WallpaperStatusListener mWallpaperStatusListener; @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { mRenderer.onSurfaceChanged(width, height); mNeedRedraw = true; } GLWallpaperSurfaceView(Context context) { super(context); setEGLContextClientVersion(2); @Override public void onSurfaceRedrawNeeded(SurfaceHolder holder) { if (mNeedRedraw) { preRender(); requestRender(); postRender(); mNeedRedraw = false; } } @Override Loading @@ -83,59 +139,83 @@ public class ImageWallpaper extends WallpaperService { } @Override public void setRenderer(Renderer renderer) { super.setRenderer(renderer); mWallpaperStatusListener = (WallpaperStatusListener) renderer; public void onStatePostChange() { // When back to home, we try to release EGL, which is preserved in lock screen or aod. if (mController.getState() == StatusBarState.SHADE) { scheduleFinishRendering(); } } @Override public void preRender() { boolean contextRecreated = false; Rect frame = getSurfaceHolder().getSurfaceFrame(); getMainThreadHandler().removeCallbacks(mFinishRenderingTask); // Check if we need to recreate egl context. if (!mEglHelper.hasEglContext()) { mEglHelper.destroyEglSurface(); if (!mEglHelper.createEglContext()) { Log.w(TAG, "recreate egl context failed!"); } else { contextRecreated = true; } } private void notifyAmbientModeChanged(boolean inAmbient, long duration) { if (mWallpaperStatusListener != null) { mWallpaperStatusListener.onAmbientModeChanged(inAmbient, duration); // Check if we need to recreate egl surface. if (mEglHelper.hasEglContext() && !mEglHelper.hasEglSurface()) { if (!mEglHelper.createEglSurface(getSurfaceHolder())) { Log.w(TAG, "recreate egl surface failed!"); } } private void notifyOffsetsChanged(float xOffset, float yOffset) { if (mWallpaperStatusListener != null) { mWallpaperStatusListener.onOffsetsChanged( xOffset, yOffset, getHolder().getSurfaceFrame()); // If we recreate egl context, notify renderer to setup again. if (mEglHelper.hasEglContext() && mEglHelper.hasEglSurface() && contextRecreated) { mRenderer.onSurfaceCreated(); mRenderer.onSurfaceChanged(frame.width(), frame.height()); } } @Override public void render() { requestRender(); public void requestRender() { Rect frame = getSurfaceHolder().getSurfaceFrame(); boolean readyToRender = mEglHelper.hasEglContext() && mEglHelper.hasEglSurface() && frame.width() > 0 && frame.height() > 0; if (readyToRender) { mRenderer.onDrawFrame(); if (!mEglHelper.swapBuffer()) { Log.e(TAG, "drawFrame failed!"); } } else { Log.e(TAG, "requestRender: not ready, has context=" + mEglHelper.hasEglContext() + ", has surface=" + mEglHelper.hasEglSurface() + ", frame=" + frame); } } /** * 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. * @param duration the duration of animation. */ void onAmbientModeChanged(boolean inAmbientMode, long duration); @Override public void postRender() { scheduleFinishRendering(); } /** * 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); private void scheduleFinishRendering() { getMainThreadHandler().removeCallbacks(mFinishRenderingTask); getMainThreadHandler().postDelayed(mFinishRenderingTask, DELAY_FINISH_RENDERING); } /** * An abstraction for view of GLRenderer. */ public interface ImageGLView { private void finishRendering() { if (mEglHelper != null) { mEglHelper.destroyEglSurface(); if (!needPreserveEglContext()) { mEglHelper.destroyEglContext(); } } } /** * Ask the view to render. */ void render(); private boolean needPreserveEglContext() { return mNeedTransition && mController != null && mController.getState() == StatusBarState.KEYGUARD; } } } packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java 0 → 100644 +230 −0 Original line number Diff line number Diff line /* * 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.EGL14.EGL_ALPHA_SIZE; import static android.opengl.EGL14.EGL_BLUE_SIZE; import static android.opengl.EGL14.EGL_CONFIG_CAVEAT; import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY; import static android.opengl.EGL14.EGL_DEPTH_SIZE; import static android.opengl.EGL14.EGL_GREEN_SIZE; import static android.opengl.EGL14.EGL_NONE; import static android.opengl.EGL14.EGL_NO_CONTEXT; import static android.opengl.EGL14.EGL_NO_DISPLAY; import static android.opengl.EGL14.EGL_NO_SURFACE; import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; import static android.opengl.EGL14.EGL_RED_SIZE; import static android.opengl.EGL14.EGL_RENDERABLE_TYPE; import static android.opengl.EGL14.EGL_STENCIL_SIZE; import static android.opengl.EGL14.EGL_SUCCESS; import static android.opengl.EGL14.eglChooseConfig; import static android.opengl.EGL14.eglCreateContext; import static android.opengl.EGL14.eglCreateWindowSurface; import static android.opengl.EGL14.eglDestroyContext; import static android.opengl.EGL14.eglDestroySurface; import static android.opengl.EGL14.eglGetDisplay; import static android.opengl.EGL14.eglGetError; import static android.opengl.EGL14.eglInitialize; import static android.opengl.EGL14.eglMakeCurrent; import static android.opengl.EGL14.eglSwapBuffers; import static android.opengl.EGL14.eglTerminate; import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLSurface; import android.opengl.GLUtils; import android.util.Log; import android.view.SurfaceHolder; /** * A helper class to handle EGL management. */ public class EglHelper { private static final String TAG = EglHelper.class.getSimpleName(); private EGLDisplay mEglDisplay; private EGLConfig mEglConfig; private EGLContext mEglContext; private EGLSurface mEglSurface; /** * Initialize EGL and prepare EglSurface. * @param surfaceHolder surface holder. * @return true if EglSurface is ready. */ public boolean init(SurfaceHolder surfaceHolder) { mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (mEglDisplay == EGL_NO_DISPLAY) { Log.w(TAG, "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } if (!eglInitialize(mEglDisplay, null, 0, null, 0)) { Log.w(TAG, "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } mEglConfig = chooseEglConfig(); if (mEglConfig == null) { Log.w(TAG, "eglConfig not initialized!"); return false; } if (!createEglContext()) { Log.w(TAG, "Can't create EGLContext!"); return false; } if (!createEglSurface(surfaceHolder)) { Log.w(TAG, "Can't create EGLSurface!"); return false; } return true; } private EGLConfig chooseEglConfig() { int[] configsCount = new int[1]; EGLConfig[] configs = new EGLConfig[1]; int[] configSpec = getConfig(); if (!eglChooseConfig(mEglDisplay, configSpec, 0, configs, 0, 1, configsCount, 0)) { Log.w(TAG, "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError())); return null; } else { if (configsCount[0] <= 0) { Log.w(TAG, "eglChooseConfig failed, invalid configs count: " + configsCount[0]); return null; } else { return configs[0]; } } } private int[] getConfig() { return new int[] { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_CONFIG_CAVEAT, EGL_NONE, EGL_NONE }; } /** * Prepare an EglSurface. * @param surfaceHolder surface holder. * @return true if EglSurface is ready. */ public boolean createEglSurface(SurfaceHolder surfaceHolder) { mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null, 0); if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { Log.w(TAG, "createWindowSurface failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { Log.w(TAG, "eglMakeCurrent failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } return true; } /** * Destroy EglSurface. */ public void destroyEglSurface() { if (hasEglSurface()) { eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(mEglDisplay, mEglSurface); mEglSurface = null; } } /** * Check if we have a valid EglSurface. * @return true if EglSurface is ready. */ public boolean hasEglSurface() { return mEglSurface != null && mEglSurface != EGL_NO_SURFACE; } /** * Prepare EglContext. * @return true if EglContext is ready. */ public boolean createEglContext() { int[] attrib_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list, 0); if (mEglContext == EGL_NO_CONTEXT) { Log.w(TAG, "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } return true; } /** * Destroy EglContext. */ public void destroyEglContext() { if (hasEglContext()) { eglDestroyContext(mEglDisplay, mEglContext); mEglContext = null; } } /** * Check if we have EglContext. * @return true if EglContext is ready. */ public boolean hasEglContext() { return mEglContext != null; } /** * Swap buffer to display. * @return true if swap successfully. */ public boolean swapBuffer() { boolean status = eglSwapBuffers(mEglDisplay, mEglSurface); int error = eglGetError(); if (error != EGL_SUCCESS) { Log.w(TAG, "eglSwapBuffers failed: " + GLUtils.getEGLErrorString(error)); } return status; } /** * Destroy EglSurface and EglContext, then terminate EGL. */ public void finish() { if (hasEglSurface()) { destroyEglSurface(); } if (hasEglContext()) { destroyEglContext(); } eglTerminate(mEglDisplay); } } packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * 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.util.Size; import android.view.SurfaceHolder; /** * A renderer which is responsible for making OpenGL calls to render a frame. */ public interface GLWallpaperRenderer { /** * Called when the surface is created or recreated. */ void onSurfaceCreated(); /** * Called when the surface changed size. * @param width surface width. * @param height surface height. */ void onSurfaceChanged(int width, int height); /** * Called to draw the current frame. */ void onDrawFrame(); /** * Notify ambient mode is changed. * @param inAmbientMode true if in ambient mode. * @param duration duration of transition. */ void updateAmbientMode(boolean inAmbientMode, long duration); /** * Ask renderer to report the surface size it needs. */ Size reportSurfaceSize(); /** * Called when no need to render any more. */ void finish(); /** * A proxy which owns surface holder. */ interface SurfaceProxy { /** * Get surface holder. * @return surface holder. */ SurfaceHolder getHolder(); /** * Ask proxy to start rendering frame to surface. */ void requestRender(); /** * Ask proxy to prepare render context. */ void preRender(); /** * Ask proxy to destroy render context. */ void postRender(); } } packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java +0 −72 Original line number Diff line number Diff line Loading @@ -195,76 +195,4 @@ class ImageGLWallpaper { glUniform1i(mUniTexture, 0); } /** * This method adjust s(x-axis), t(y-axis) texture coordinates * to prevent the wallpaper from being stretched. * The adjustment happens if either the width or height of the bitmap is larger than * corresponding size of the surface. * If both width and height are larger than corresponding size of the surface, * the adjustment will happen at both s, t side. * * @param bitmapWidth The width of the bitmap. * @param bitmapHeight The height of the bitmap. * @param surfaceWidth The width of the surface. * @param surfaceHeight The height of the surface. * @param xOffset The offset amount along s axis. * @param yOffset The offset amount along t axis. */ void adjustTextureCoordinates(int bitmapWidth, int bitmapHeight, int surfaceWidth, int surfaceHeight, float xOffset, float yOffset) { float[] coordinates = TEXTURES.clone(); if (bitmapWidth > surfaceWidth) { // Calculate the new s pos in pixels. float pixelS = (float) Math.round((bitmapWidth - surfaceWidth) * xOffset); // Calculate the s pos in texture coordinate. float coordinateS = pixelS / bitmapWidth; // Calculate the percentage occupied by the surface width in bitmap width. float surfacePercentageW = (float) surfaceWidth / bitmapWidth; // Need also consider the case if bitmap height is smaller than surface height. if (bitmapHeight < surfaceHeight) { // We will narrow the surface percentage to keep aspect ratio. surfacePercentageW *= (float) bitmapHeight / surfaceHeight; } // Determine the final s pos, also limit the legal s pos to prevent from out of range. float s = coordinateS + surfacePercentageW > 1f ? 1f - surfacePercentageW : coordinateS; // Traverse the s pos in texture coordinates array and adjust the s pos accordingly. for (int i = 0; i < coordinates.length; i += 2) { // indices 2, 4 and 6 are the end of s coordinates. if (i == 2 || i == 4 || i == 6) { coordinates[i] = Math.min(1f, s + surfacePercentageW); } else { coordinates[i] = s; } } } if (bitmapHeight > surfaceHeight) { // Calculate the new t pos in pixels. float pixelT = (float) Math.round((bitmapHeight - surfaceHeight) * yOffset); // Calculate the t pos in texture coordinate. float coordinateT = pixelT / bitmapHeight; // Calculate the percentage occupied by the surface height in bitmap height. float surfacePercentageH = (float) surfaceHeight / bitmapHeight; // Need also consider the case if bitmap width is smaller than surface width. if (bitmapWidth < surfaceWidth) { // We will narrow the surface percentage to keep aspect ratio. surfacePercentageH *= (float) bitmapWidth / surfaceWidth; } // Determine the final t pos, also limit the legal t pos to prevent from out of range. float t = coordinateT + surfacePercentageH > 1f ? 1f - surfacePercentageH : coordinateT; // Traverse the t pos in texture coordinates array and adjust the t pos accordingly. for (int i = 1; i < coordinates.length; i += 2) { // indices 1, 3 and 11 are the end of t coordinates. if (i == 1 || i == 3 || i == 11) { coordinates[i] = Math.min(1f, t + surfacePercentageH); } else { coordinates[i] = t; } } } mTextureBuffer.put(coordinates); mTextureBuffer.position(0); } } packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java +19 −6 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +150 −70 Original line number Diff line number Diff line Loading @@ -16,13 +16,22 @@ package com.android.systemui; import android.app.ActivityManager; import android.content.Context; import android.graphics.Rect; import android.opengl.GLSurfaceView; import android.service.wallpaper.WallpaperService; import android.util.Log; import android.util.Size; import android.view.SurfaceHolder; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.glwallpaper.EglHelper; import com.android.systemui.glwallpaper.GLWallpaperRenderer; import com.android.systemui.glwallpaper.ImageWallpaperRenderer; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.DozeParameters; /** * Default built-in wallpaper that simply shows a static image. Loading @@ -30,51 +39,98 @@ import com.android.systemui.glwallpaper.ImageWallpaperRenderer; @SuppressWarnings({"UnusedDeclaration"}) public class ImageWallpaper extends WallpaperService { private static final String TAG = ImageWallpaper.class.getSimpleName(); // We delayed destroy render context that subsequent render requests have chance to cancel it. // This is to avoid destroying then recreating render context in a very short time. private static final int DELAY_FINISH_RENDERING = 1000; @Override public Engine onCreateEngine() { return new GLEngine(this); } class GLEngine extends Engine { private GLWallpaperSurfaceView mWallpaperSurfaceView; class GLEngine extends Engine implements GLWallpaperRenderer.SurfaceProxy, StateListener { // Surface is rejected if size below a threshold on some devices (ie. 8px on elfin) // set min to 64 px (CTS covers this), please refer to ag/4867989 for detail. @VisibleForTesting static final int MIN_SURFACE_WIDTH = 64; @VisibleForTesting static final int MIN_SURFACE_HEIGHT = 64; private GLWallpaperRenderer mRenderer; private EglHelper mEglHelper; private StatusBarStateController mController; private final Runnable mFinishRenderingTask = this::finishRendering; private final boolean mNeedTransition; private boolean mNeedRedraw; GLEngine(Context context) { mWallpaperSurfaceView = new GLWallpaperSurfaceView(context); mWallpaperSurfaceView.setRenderer( new ImageWallpaperRenderer(context, mWallpaperSurfaceView)); mWallpaperSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); setOffsetNotificationsEnabled(true); mNeedTransition = ActivityManager.isHighEndGfx() && !DozeParameters.getInstance(context).getDisplayNeedsBlanking(); // We will preserve EGL context when we are in lock screen or aod // to avoid janking in following transition, we need to release when back to home. mController = Dependency.get(StatusBarStateController.class); if (mController != null) { mController.addCallback(this /* StateListener */); } mEglHelper = new EglHelper(); mRenderer = new ImageWallpaperRenderer(context, this /* SurfaceProxy */); } @Override public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { if (mWallpaperSurfaceView != null) { mWallpaperSurfaceView.notifyAmbientModeChanged(inAmbientMode, animationDuration); public void onCreate(SurfaceHolder surfaceHolder) { setFixedSizeAllowed(true); setOffsetNotificationsEnabled(false); updateSurfaceSize(); } private void updateSurfaceSize() { SurfaceHolder holder = getSurfaceHolder(); Size frameSize = mRenderer.reportSurfaceSize(); int width = Math.max(MIN_SURFACE_WIDTH, frameSize.getWidth()); int height = Math.max(MIN_SURFACE_HEIGHT, frameSize.getHeight()); holder.setFixedSize(width, height); } @Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { if (mWallpaperSurfaceView != null) { mWallpaperSurfaceView.notifyOffsetsChanged(xOffset, yOffset); } public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { mRenderer.updateAmbientMode(inAmbientMode, (mNeedTransition || animationDuration != 0) ? animationDuration : 0); } @Override public void onDestroy() { if (mWallpaperSurfaceView != null) { mWallpaperSurfaceView.onPause(); if (mController != null) { mController.removeCallback(this /* StateListener */); } mController = null; mRenderer.finish(); mRenderer = null; mEglHelper.finish(); mEglHelper = null; getSurfaceHolder().getSurface().hwuiDestroy(); } @Override public void onSurfaceCreated(SurfaceHolder holder) { mEglHelper.init(holder); mRenderer.onSurfaceCreated(); } private class GLWallpaperSurfaceView extends GLSurfaceView implements ImageGLView { private WallpaperStatusListener mWallpaperStatusListener; @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { mRenderer.onSurfaceChanged(width, height); mNeedRedraw = true; } GLWallpaperSurfaceView(Context context) { super(context); setEGLContextClientVersion(2); @Override public void onSurfaceRedrawNeeded(SurfaceHolder holder) { if (mNeedRedraw) { preRender(); requestRender(); postRender(); mNeedRedraw = false; } } @Override Loading @@ -83,59 +139,83 @@ public class ImageWallpaper extends WallpaperService { } @Override public void setRenderer(Renderer renderer) { super.setRenderer(renderer); mWallpaperStatusListener = (WallpaperStatusListener) renderer; public void onStatePostChange() { // When back to home, we try to release EGL, which is preserved in lock screen or aod. if (mController.getState() == StatusBarState.SHADE) { scheduleFinishRendering(); } } @Override public void preRender() { boolean contextRecreated = false; Rect frame = getSurfaceHolder().getSurfaceFrame(); getMainThreadHandler().removeCallbacks(mFinishRenderingTask); // Check if we need to recreate egl context. if (!mEglHelper.hasEglContext()) { mEglHelper.destroyEglSurface(); if (!mEglHelper.createEglContext()) { Log.w(TAG, "recreate egl context failed!"); } else { contextRecreated = true; } } private void notifyAmbientModeChanged(boolean inAmbient, long duration) { if (mWallpaperStatusListener != null) { mWallpaperStatusListener.onAmbientModeChanged(inAmbient, duration); // Check if we need to recreate egl surface. if (mEglHelper.hasEglContext() && !mEglHelper.hasEglSurface()) { if (!mEglHelper.createEglSurface(getSurfaceHolder())) { Log.w(TAG, "recreate egl surface failed!"); } } private void notifyOffsetsChanged(float xOffset, float yOffset) { if (mWallpaperStatusListener != null) { mWallpaperStatusListener.onOffsetsChanged( xOffset, yOffset, getHolder().getSurfaceFrame()); // If we recreate egl context, notify renderer to setup again. if (mEglHelper.hasEglContext() && mEglHelper.hasEglSurface() && contextRecreated) { mRenderer.onSurfaceCreated(); mRenderer.onSurfaceChanged(frame.width(), frame.height()); } } @Override public void render() { requestRender(); public void requestRender() { Rect frame = getSurfaceHolder().getSurfaceFrame(); boolean readyToRender = mEglHelper.hasEglContext() && mEglHelper.hasEglSurface() && frame.width() > 0 && frame.height() > 0; if (readyToRender) { mRenderer.onDrawFrame(); if (!mEglHelper.swapBuffer()) { Log.e(TAG, "drawFrame failed!"); } } else { Log.e(TAG, "requestRender: not ready, has context=" + mEglHelper.hasEglContext() + ", has surface=" + mEglHelper.hasEglSurface() + ", frame=" + frame); } } /** * 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. * @param duration the duration of animation. */ void onAmbientModeChanged(boolean inAmbientMode, long duration); @Override public void postRender() { scheduleFinishRendering(); } /** * 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); private void scheduleFinishRendering() { getMainThreadHandler().removeCallbacks(mFinishRenderingTask); getMainThreadHandler().postDelayed(mFinishRenderingTask, DELAY_FINISH_RENDERING); } /** * An abstraction for view of GLRenderer. */ public interface ImageGLView { private void finishRendering() { if (mEglHelper != null) { mEglHelper.destroyEglSurface(); if (!needPreserveEglContext()) { mEglHelper.destroyEglContext(); } } } /** * Ask the view to render. */ void render(); private boolean needPreserveEglContext() { return mNeedTransition && mController != null && mController.getState() == StatusBarState.KEYGUARD; } } }
packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java 0 → 100644 +230 −0 Original line number Diff line number Diff line /* * 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.EGL14.EGL_ALPHA_SIZE; import static android.opengl.EGL14.EGL_BLUE_SIZE; import static android.opengl.EGL14.EGL_CONFIG_CAVEAT; import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY; import static android.opengl.EGL14.EGL_DEPTH_SIZE; import static android.opengl.EGL14.EGL_GREEN_SIZE; import static android.opengl.EGL14.EGL_NONE; import static android.opengl.EGL14.EGL_NO_CONTEXT; import static android.opengl.EGL14.EGL_NO_DISPLAY; import static android.opengl.EGL14.EGL_NO_SURFACE; import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; import static android.opengl.EGL14.EGL_RED_SIZE; import static android.opengl.EGL14.EGL_RENDERABLE_TYPE; import static android.opengl.EGL14.EGL_STENCIL_SIZE; import static android.opengl.EGL14.EGL_SUCCESS; import static android.opengl.EGL14.eglChooseConfig; import static android.opengl.EGL14.eglCreateContext; import static android.opengl.EGL14.eglCreateWindowSurface; import static android.opengl.EGL14.eglDestroyContext; import static android.opengl.EGL14.eglDestroySurface; import static android.opengl.EGL14.eglGetDisplay; import static android.opengl.EGL14.eglGetError; import static android.opengl.EGL14.eglInitialize; import static android.opengl.EGL14.eglMakeCurrent; import static android.opengl.EGL14.eglSwapBuffers; import static android.opengl.EGL14.eglTerminate; import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLSurface; import android.opengl.GLUtils; import android.util.Log; import android.view.SurfaceHolder; /** * A helper class to handle EGL management. */ public class EglHelper { private static final String TAG = EglHelper.class.getSimpleName(); private EGLDisplay mEglDisplay; private EGLConfig mEglConfig; private EGLContext mEglContext; private EGLSurface mEglSurface; /** * Initialize EGL and prepare EglSurface. * @param surfaceHolder surface holder. * @return true if EglSurface is ready. */ public boolean init(SurfaceHolder surfaceHolder) { mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (mEglDisplay == EGL_NO_DISPLAY) { Log.w(TAG, "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } if (!eglInitialize(mEglDisplay, null, 0, null, 0)) { Log.w(TAG, "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } mEglConfig = chooseEglConfig(); if (mEglConfig == null) { Log.w(TAG, "eglConfig not initialized!"); return false; } if (!createEglContext()) { Log.w(TAG, "Can't create EGLContext!"); return false; } if (!createEglSurface(surfaceHolder)) { Log.w(TAG, "Can't create EGLSurface!"); return false; } return true; } private EGLConfig chooseEglConfig() { int[] configsCount = new int[1]; EGLConfig[] configs = new EGLConfig[1]; int[] configSpec = getConfig(); if (!eglChooseConfig(mEglDisplay, configSpec, 0, configs, 0, 1, configsCount, 0)) { Log.w(TAG, "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError())); return null; } else { if (configsCount[0] <= 0) { Log.w(TAG, "eglChooseConfig failed, invalid configs count: " + configsCount[0]); return null; } else { return configs[0]; } } } private int[] getConfig() { return new int[] { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_CONFIG_CAVEAT, EGL_NONE, EGL_NONE }; } /** * Prepare an EglSurface. * @param surfaceHolder surface holder. * @return true if EglSurface is ready. */ public boolean createEglSurface(SurfaceHolder surfaceHolder) { mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null, 0); if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { Log.w(TAG, "createWindowSurface failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { Log.w(TAG, "eglMakeCurrent failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } return true; } /** * Destroy EglSurface. */ public void destroyEglSurface() { if (hasEglSurface()) { eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(mEglDisplay, mEglSurface); mEglSurface = null; } } /** * Check if we have a valid EglSurface. * @return true if EglSurface is ready. */ public boolean hasEglSurface() { return mEglSurface != null && mEglSurface != EGL_NO_SURFACE; } /** * Prepare EglContext. * @return true if EglContext is ready. */ public boolean createEglContext() { int[] attrib_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list, 0); if (mEglContext == EGL_NO_CONTEXT) { Log.w(TAG, "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError())); return false; } return true; } /** * Destroy EglContext. */ public void destroyEglContext() { if (hasEglContext()) { eglDestroyContext(mEglDisplay, mEglContext); mEglContext = null; } } /** * Check if we have EglContext. * @return true if EglContext is ready. */ public boolean hasEglContext() { return mEglContext != null; } /** * Swap buffer to display. * @return true if swap successfully. */ public boolean swapBuffer() { boolean status = eglSwapBuffers(mEglDisplay, mEglSurface); int error = eglGetError(); if (error != EGL_SUCCESS) { Log.w(TAG, "eglSwapBuffers failed: " + GLUtils.getEGLErrorString(error)); } return status; } /** * Destroy EglSurface and EglContext, then terminate EGL. */ public void finish() { if (hasEglSurface()) { destroyEglSurface(); } if (hasEglContext()) { destroyEglContext(); } eglTerminate(mEglDisplay); } }
packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * 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.util.Size; import android.view.SurfaceHolder; /** * A renderer which is responsible for making OpenGL calls to render a frame. */ public interface GLWallpaperRenderer { /** * Called when the surface is created or recreated. */ void onSurfaceCreated(); /** * Called when the surface changed size. * @param width surface width. * @param height surface height. */ void onSurfaceChanged(int width, int height); /** * Called to draw the current frame. */ void onDrawFrame(); /** * Notify ambient mode is changed. * @param inAmbientMode true if in ambient mode. * @param duration duration of transition. */ void updateAmbientMode(boolean inAmbientMode, long duration); /** * Ask renderer to report the surface size it needs. */ Size reportSurfaceSize(); /** * Called when no need to render any more. */ void finish(); /** * A proxy which owns surface holder. */ interface SurfaceProxy { /** * Get surface holder. * @return surface holder. */ SurfaceHolder getHolder(); /** * Ask proxy to start rendering frame to surface. */ void requestRender(); /** * Ask proxy to prepare render context. */ void preRender(); /** * Ask proxy to destroy render context. */ void postRender(); } }
packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java +0 −72 Original line number Diff line number Diff line Loading @@ -195,76 +195,4 @@ class ImageGLWallpaper { glUniform1i(mUniTexture, 0); } /** * This method adjust s(x-axis), t(y-axis) texture coordinates * to prevent the wallpaper from being stretched. * The adjustment happens if either the width or height of the bitmap is larger than * corresponding size of the surface. * If both width and height are larger than corresponding size of the surface, * the adjustment will happen at both s, t side. * * @param bitmapWidth The width of the bitmap. * @param bitmapHeight The height of the bitmap. * @param surfaceWidth The width of the surface. * @param surfaceHeight The height of the surface. * @param xOffset The offset amount along s axis. * @param yOffset The offset amount along t axis. */ void adjustTextureCoordinates(int bitmapWidth, int bitmapHeight, int surfaceWidth, int surfaceHeight, float xOffset, float yOffset) { float[] coordinates = TEXTURES.clone(); if (bitmapWidth > surfaceWidth) { // Calculate the new s pos in pixels. float pixelS = (float) Math.round((bitmapWidth - surfaceWidth) * xOffset); // Calculate the s pos in texture coordinate. float coordinateS = pixelS / bitmapWidth; // Calculate the percentage occupied by the surface width in bitmap width. float surfacePercentageW = (float) surfaceWidth / bitmapWidth; // Need also consider the case if bitmap height is smaller than surface height. if (bitmapHeight < surfaceHeight) { // We will narrow the surface percentage to keep aspect ratio. surfacePercentageW *= (float) bitmapHeight / surfaceHeight; } // Determine the final s pos, also limit the legal s pos to prevent from out of range. float s = coordinateS + surfacePercentageW > 1f ? 1f - surfacePercentageW : coordinateS; // Traverse the s pos in texture coordinates array and adjust the s pos accordingly. for (int i = 0; i < coordinates.length; i += 2) { // indices 2, 4 and 6 are the end of s coordinates. if (i == 2 || i == 4 || i == 6) { coordinates[i] = Math.min(1f, s + surfacePercentageW); } else { coordinates[i] = s; } } } if (bitmapHeight > surfaceHeight) { // Calculate the new t pos in pixels. float pixelT = (float) Math.round((bitmapHeight - surfaceHeight) * yOffset); // Calculate the t pos in texture coordinate. float coordinateT = pixelT / bitmapHeight; // Calculate the percentage occupied by the surface height in bitmap height. float surfacePercentageH = (float) surfaceHeight / bitmapHeight; // Need also consider the case if bitmap width is smaller than surface width. if (bitmapWidth < surfaceWidth) { // We will narrow the surface percentage to keep aspect ratio. surfacePercentageH *= (float) bitmapWidth / surfaceWidth; } // Determine the final t pos, also limit the legal t pos to prevent from out of range. float t = coordinateT + surfacePercentageH > 1f ? 1f - surfacePercentageH : coordinateT; // Traverse the t pos in texture coordinates array and adjust the t pos accordingly. for (int i = 1; i < coordinates.length; i += 2) { // indices 1, 3 and 11 are the end of t coordinates. if (i == 1 || i == 3 || i == 11) { coordinates[i] = Math.min(1f, t + surfacePercentageH); } else { coordinates[i] = t; } } } mTextureBuffer.put(coordinates); mTextureBuffer.position(0); } }
packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java +19 −6 File changed.Preview size limit exceeded, changes collapsed. Show changes