1 /* 2 * Copyright (C) 2020 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.car.pm.blurredbackground; 18 19 import android.content.Context; 20 import android.graphics.Rect; 21 import android.graphics.SurfaceTexture; 22 import android.opengl.GLES11Ext; 23 import android.opengl.GLES30; 24 import android.opengl.GLSurfaceView; 25 import android.os.IBinder; 26 import android.util.Slog; 27 import android.view.Surface; 28 import android.view.SurfaceControl; 29 30 import com.android.car.CarLog; 31 import com.android.car.R; 32 33 import java.nio.IntBuffer; 34 35 import javax.microedition.khronos.egl.EGLConfig; 36 import javax.microedition.khronos.opengles.GL10; 37 38 /** 39 * The renderer class for the {@link GLSurfaceView} of the {@link ActivityBlockingActivity} 40 */ 41 public class BlurredSurfaceRenderer implements GLSurfaceView.Renderer { 42 43 private static final String TAG = CarLog.tagFor(BlurredSurfaceRenderer.class); 44 private static final int NUM_INDICES_TO_RENDER = 4; 45 46 private final String mVertexShader; 47 private final String mHorizontalBlurShader; 48 private final String mVerticalBlurShader; 49 private final Rect mWindowRect; 50 51 private BlurTextureProgram mProgram; 52 private SurfaceTexture mSurfaceTexture; 53 private Surface mSurface; 54 55 private int mScreenshotTextureId; 56 private final IntBuffer mScreenshotTextureBuffer = IntBuffer.allocate(1); 57 private final float[] mTexMatrix = new float[16]; 58 59 private final boolean mShadersLoadedSuccessfully; 60 private final boolean mShouldRenderBlurred; 61 private boolean mIsScreenShotCaptured = false; 62 63 /** 64 * Constructs a new {@link BlurredSurfaceRenderer} and loads the shaders 65 * needed for rendering a blurred texture 66 * 67 * @param windowRect Rect that represents the application window 68 */ BlurredSurfaceRenderer(Context context, Rect windowRect, boolean shouldRenderBlurred)69 public BlurredSurfaceRenderer(Context context, Rect windowRect, boolean shouldRenderBlurred) { 70 mShouldRenderBlurred = shouldRenderBlurred; 71 72 mVertexShader = GLHelper.getShaderFromRaw(context, R.raw.vertex_shader); 73 mHorizontalBlurShader = GLHelper.getShaderFromRaw(context, 74 R.raw.horizontal_blur_fragment_shader); 75 mVerticalBlurShader = GLHelper.getShaderFromRaw(context, 76 R.raw.vertical_blur_fragment_shader); 77 78 mShadersLoadedSuccessfully = mVertexShader != null 79 && mHorizontalBlurShader != null 80 && mVerticalBlurShader != null; 81 82 mWindowRect = windowRect; 83 } 84 85 @Override onSurfaceCreated(GL10 gl, EGLConfig config)86 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 87 mScreenshotTextureId = GLHelper.createAndBindTextureObject(mScreenshotTextureBuffer, 88 GLES11Ext.GL_TEXTURE_EXTERNAL_OES); 89 90 mSurfaceTexture = new SurfaceTexture(mScreenshotTextureId); 91 mSurface = new Surface(mSurfaceTexture); 92 93 if (mShouldRenderBlurred) { 94 mIsScreenShotCaptured = captureScreenshot(); 95 } 96 } 97 98 @Override onSurfaceChanged(GL10 gl, int width, int height)99 public void onSurfaceChanged(GL10 gl, int width, int height) { 100 } 101 102 @Override onDrawFrame(GL10 gl)103 public void onDrawFrame(GL10 gl) { 104 if (shouldDrawFrame()) { 105 mProgram = new BlurTextureProgram( 106 mScreenshotTextureBuffer, 107 mTexMatrix, 108 mVertexShader, 109 mHorizontalBlurShader, 110 mVerticalBlurShader, 111 mWindowRect 112 ); 113 mProgram.render(); 114 } else { 115 logWillNotRenderBlurredMsg(); 116 117 // If we determine we shouldn't render a blurred texture, we 118 // will default to rendering a transparent GLSurfaceView so that 119 // the ActivityBlockingActivity appears translucent 120 renderTransparent(); 121 } 122 } 123 renderTransparent()124 private void renderTransparent() { 125 GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT); 126 GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, /*first index to render */ 0, 127 NUM_INDICES_TO_RENDER); 128 } 129 130 /** 131 * Called when the ActivityBlockingActivity pauses 132 * cleans up the OpenGL program 133 */ onPause()134 public void onPause() { 135 if (mProgram != null) { 136 mProgram.cleanupResources(); 137 } 138 deleteScreenshotTexture(); 139 } 140 captureScreenshot()141 private boolean captureScreenshot() { 142 boolean isScreenshotCaptured = false; 143 144 try { 145 final IBinder token = SurfaceControl.getInternalDisplayToken(); 146 if (token == null) { 147 Slog.e(TAG, 148 "Could not find display token for screenshot. Will not capture screenshot"); 149 } else { 150 final SurfaceControl.DisplayCaptureArgs captureArgs = 151 new SurfaceControl.DisplayCaptureArgs.Builder(token) 152 .setSize(mWindowRect.width(), mWindowRect.height()) 153 .setSourceCrop(mWindowRect) 154 .setUseIdentityTransform(true) 155 .build(); 156 157 SurfaceControl.ScreenshotHardwareBuffer screenshotHardwareBuffer = 158 SurfaceControl.captureDisplay(captureArgs); 159 mSurface.attachAndQueueBufferWithColorSpace( 160 screenshotHardwareBuffer.getHardwareBuffer(), 161 screenshotHardwareBuffer.getColorSpace()); 162 mSurfaceTexture.updateTexImage(); 163 mSurfaceTexture.getTransformMatrix(mTexMatrix); 164 isScreenshotCaptured = true; 165 } 166 167 } finally { 168 mSurface.release(); 169 mSurfaceTexture.release(); 170 } 171 172 return isScreenshotCaptured; 173 } 174 deleteScreenshotTexture()175 private void deleteScreenshotTexture() { 176 GLES30.glDeleteTextures(mScreenshotTextureBuffer.capacity(), mScreenshotTextureBuffer); 177 GLHelper.checkGlErrors("glDeleteTextures"); 178 179 mIsScreenShotCaptured = false; 180 } 181 logWillNotRenderBlurredMsg()182 private void logWillNotRenderBlurredMsg() { 183 if (!mIsScreenShotCaptured) { 184 Slog.e(TAG, "Screenshot was not captured. Will not render blurred surface"); 185 } 186 if (!mShadersLoadedSuccessfully) { 187 Slog.e(TAG, "Shaders were not loaded successfully. Will not render blurred surface"); 188 } 189 } 190 shouldDrawFrame()191 private boolean shouldDrawFrame() { 192 return mIsScreenShotCaptured 193 && mShadersLoadedSuccessfully 194 && mShouldRenderBlurred; 195 } 196 } 197 198