SurfaceViewWrapper.java (5670B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 package org.mozilla.gecko; 6 7 import android.content.Context; 8 import android.graphics.Color; 9 import android.graphics.PixelFormat; 10 import android.graphics.SurfaceTexture; 11 import android.os.Build; 12 import android.util.Log; 13 import android.view.Surface; 14 import android.view.SurfaceControl; 15 import android.view.SurfaceHolder; 16 import android.view.SurfaceView; 17 import android.view.TextureView; 18 import android.view.View; 19 20 /** Provides transparent access to either a SurfaceView or TextureView */ 21 public class SurfaceViewWrapper { 22 private static final String LOGTAG = "SurfaceViewWrapper"; 23 24 private ListenerWrapper mListenerWrapper; 25 private View mView; 26 27 // Only one of these will be non-null at any point in time 28 SurfaceView mSurfaceView; 29 TextureView mTextureView; 30 31 public SurfaceViewWrapper(final Context context) { 32 // By default, use SurfaceView 33 mListenerWrapper = new ListenerWrapper(); 34 initSurfaceView(context); 35 } 36 37 private void initSurfaceView(final Context context) { 38 mSurfaceView = new MagnifiableSurfaceView(context); 39 mSurfaceView.setBackgroundColor(Color.TRANSPARENT); 40 mSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT); 41 mView = mSurfaceView; 42 } 43 44 public void useSurfaceView(final Context context) { 45 if (mTextureView != null) { 46 mListenerWrapper.onSurfaceTextureDestroyed(mTextureView.getSurfaceTexture()); 47 mTextureView = null; 48 } 49 mListenerWrapper.reset(); 50 initSurfaceView(context); 51 } 52 53 public void useTextureView(final Context context) { 54 if (mSurfaceView != null) { 55 mListenerWrapper.surfaceDestroyed(mSurfaceView.getHolder()); 56 mSurfaceView = null; 57 } 58 mListenerWrapper.reset(); 59 mTextureView = new TextureView(context); 60 mTextureView.setSurfaceTextureListener(mListenerWrapper); 61 mView = mTextureView; 62 } 63 64 public void setBackgroundColor(final int color) { 65 if (mSurfaceView != null) { 66 mSurfaceView.setBackgroundColor(color); 67 } else { 68 Log.e(LOGTAG, "TextureView doesn't support background color."); 69 } 70 } 71 72 public void setListener(final Listener listener) { 73 mListenerWrapper.mListener = listener; 74 mSurfaceView.getHolder().addCallback(mListenerWrapper); 75 } 76 77 public int getWidth() { 78 if (mSurfaceView != null) { 79 return mSurfaceView.getHolder().getSurfaceFrame().right; 80 } 81 return mListenerWrapper.mWidth; 82 } 83 84 public int getHeight() { 85 if (mSurfaceView != null) { 86 return mSurfaceView.getHolder().getSurfaceFrame().bottom; 87 } 88 return mListenerWrapper.mHeight; 89 } 90 91 /** 92 * Returns the SurfaceControl associated with the SurfaceView, or null on unsupported SDK versions 93 * or when using the TextureView backend. 94 */ 95 public SurfaceControl getSurfaceControl() { 96 if (mSurfaceView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 97 return mSurfaceView.getSurfaceControl(); 98 } 99 100 return null; 101 } 102 103 public Surface getSurface() { 104 if (mSurfaceView != null) { 105 return mSurfaceView.getHolder().getSurface(); 106 } 107 108 return mListenerWrapper.mSurface; 109 } 110 111 public View getView() { 112 return mView; 113 } 114 115 /** 116 * Translates SurfaceTextureListener and SurfaceHolder.Callback into a common interface 117 * SurfaceViewWrapper.Listener 118 */ 119 private class ListenerWrapper 120 implements TextureView.SurfaceTextureListener, SurfaceHolder.Callback { 121 private Listener mListener; 122 123 // TextureView doesn't provide getters for these so we keep track of them here 124 private Surface mSurface; 125 private int mWidth; 126 private int mHeight; 127 128 public void reset() { 129 mWidth = 0; 130 mHeight = 0; 131 mSurface = null; 132 } 133 134 // TextureView 135 @Override 136 public void onSurfaceTextureAvailable( 137 final SurfaceTexture surface, final int width, final int height) { 138 mSurface = new Surface(surface); 139 mWidth = width; 140 mHeight = height; 141 if (mListener != null) { 142 mListener.onSurfaceChanged(mSurface, null, width, height); 143 } 144 } 145 146 @Override 147 public void onSurfaceTextureSizeChanged( 148 final SurfaceTexture surface, final int width, final int height) { 149 mWidth = width; 150 mHeight = height; 151 if (mListener != null) { 152 mListener.onSurfaceChanged(mSurface, null, mWidth, mHeight); 153 } 154 } 155 156 @Override 157 public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) { 158 if (mListener != null) { 159 mListener.onSurfaceDestroyed(); 160 } 161 mSurface = null; 162 return false; 163 } 164 165 @Override 166 public void onSurfaceTextureUpdated(final SurfaceTexture surface) { 167 mSurface = new Surface(surface); 168 if (mListener != null) { 169 mListener.onSurfaceChanged(mSurface, null, mWidth, mHeight); 170 } 171 } 172 173 // SurfaceView 174 @Override 175 public void surfaceCreated(final SurfaceHolder holder) {} 176 177 @Override 178 public void surfaceChanged( 179 final SurfaceHolder holder, final int format, final int width, final int height) { 180 if (mListener != null) { 181 mListener.onSurfaceChanged(holder.getSurface(), getSurfaceControl(), width, height); 182 } 183 } 184 185 @Override 186 public void surfaceDestroyed(final SurfaceHolder holder) { 187 if (mListener != null) { 188 mListener.onSurfaceDestroyed(); 189 } 190 } 191 } 192 193 public interface Listener { 194 void onSurfaceChanged(Surface surface, SurfaceControl surfaceControl, int width, int height); 195 196 void onSurfaceDestroyed(); 197 } 198 }