• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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