ContentViewRenderView.java revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.content.browser; 6 7import android.content.Context; 8import android.graphics.Color; 9import android.graphics.PixelFormat; 10import android.view.Surface; 11import android.view.SurfaceHolder; 12import android.view.SurfaceView; 13import android.widget.FrameLayout; 14 15import org.chromium.base.CalledByNative; 16import org.chromium.base.JNINamespace; 17import org.chromium.ui.base.WindowAndroid; 18 19import java.util.ArrayList; 20import java.util.List; 21 22/*** 23 * This view is used by a ContentView to render its content. 24 * Call {@link #setCurrentContentViewCore(ContentViewCore)} with the contentViewCore that should be 25 * managing the view. 26 * Note that only one ContentViewCore can be shown at a time. 27 */ 28@JNINamespace("content") 29public class ContentViewRenderView extends FrameLayout { 30 // The native side of this object. 31 private long mNativeContentViewRenderView; 32 private SurfaceHolder.Callback mSurfaceCallback; 33 private List<DelayedSurfaceRunnable> mDelayedSurfaceRunnableList; 34 35 private final SurfaceView mSurfaceView; 36 protected ContentViewCore mContentViewCore; 37 38 private ContentReadbackHandler mContentReadbackHandler; 39 40 /** 41 * Constructing the SurfaceView early sends surface created notifications 42 * before the native library is loaded. This runnable sends the same signals after 43 * the library is loaded. 44 */ 45 private class DelayedSurfaceRunnable implements Runnable { 46 private final SurfaceHolder mHolder; 47 private final int mFormat; 48 private final int mWidth; 49 private final int mHeight; 50 51 /** 52 * see https://developer.android.com/reference/android/view/SurfaceHolder.Callback.html# 53 * surfaceChanged(android.view.SurfaceHolder, int, int, int) 54 */ 55 public DelayedSurfaceRunnable(SurfaceHolder holder, int format, int width, int height) { 56 mHolder = holder; 57 mFormat = format; 58 mWidth = width; 59 mHeight = height; 60 } 61 62 @Override 63 public void run() { 64 assert mNativeContentViewRenderView != 0; 65 nativeSurfaceChanged(mNativeContentViewRenderView, mFormat, mWidth, mHeight, 66 mHolder.getSurface()); 67 if (mContentViewCore != null) { 68 mContentViewCore.onPhysicalBackingSizeChanged(mWidth, mHeight); 69 } 70 } 71 } 72 73 /** 74 * Constructs a new ContentViewRenderView. 75 * This should be called and the {@link ContentViewRenderView} should be added to the view 76 * hierarchy before the first draw to avoid a black flash that is seen every time a 77 * {@link SurfaceView} is added. 78 * @param context The context used to create this. 79 */ 80 public ContentViewRenderView(Context context) { 81 super(context); 82 83 mSurfaceView = createSurfaceView(getContext()); 84 mSurfaceView.setZOrderMediaOverlay(true); 85 86 setSurfaceViewBackgroundColor(Color.WHITE); 87 88 // Add a placeholder callback which will keep track of the last surfaceChanged call if we 89 // get any until the native libraries have been loaded. 90 mSurfaceCallback = new SurfaceHolder.Callback() { 91 @Override 92 public void surfaceDestroyed(SurfaceHolder holder) { 93 mDelayedSurfaceRunnableList = null; 94 } 95 96 @Override 97 public void surfaceCreated(SurfaceHolder holder) { 98 mDelayedSurfaceRunnableList = 99 new ArrayList<ContentViewRenderView.DelayedSurfaceRunnable>(); 100 } 101 102 @Override 103 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 104 mDelayedSurfaceRunnableList.add( 105 new DelayedSurfaceRunnable(holder, format, width, height)); 106 return; 107 } 108 }; 109 mSurfaceView.getHolder().addCallback(mSurfaceCallback); 110 111 addView(mSurfaceView, 112 new FrameLayout.LayoutParams( 113 FrameLayout.LayoutParams.MATCH_PARENT, 114 FrameLayout.LayoutParams.MATCH_PARENT)); 115 } 116 117 /** 118 * Initialization that requires native libraries should be done here. 119 * Native code should add/remove the layers to be rendered through the ContentViewLayerRenderer. 120 * @param rootWindow The {@link WindowAndroid} this render view should be linked to. 121 */ 122 public void onNativeLibraryLoaded(WindowAndroid rootWindow) { 123 assert rootWindow != null; 124 mNativeContentViewRenderView = nativeInit(rootWindow.getNativePointer()); 125 assert mNativeContentViewRenderView != 0; 126 mSurfaceView.getHolder().removeCallback(mSurfaceCallback); 127 mSurfaceCallback = new SurfaceHolder.Callback() { 128 @Override 129 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 130 assert mNativeContentViewRenderView != 0; 131 nativeSurfaceChanged(mNativeContentViewRenderView, 132 format, width, height, holder.getSurface()); 133 if (mContentViewCore != null) { 134 mContentViewCore.onPhysicalBackingSizeChanged( 135 width, height); 136 } 137 } 138 139 @Override 140 public void surfaceCreated(SurfaceHolder holder) { 141 assert mNativeContentViewRenderView != 0; 142 nativeSurfaceCreated(mNativeContentViewRenderView); 143 144 onReadyToRender(); 145 } 146 147 @Override 148 public void surfaceDestroyed(SurfaceHolder holder) { 149 assert mNativeContentViewRenderView != 0; 150 nativeSurfaceDestroyed(mNativeContentViewRenderView); 151 } 152 }; 153 mSurfaceView.getHolder().addCallback(mSurfaceCallback); 154 155 mContentReadbackHandler = new ContentReadbackHandler() { 156 @Override 157 protected boolean readyForReadback() { 158 return mNativeContentViewRenderView != 0 && mContentViewCore != null; 159 } 160 }; 161 mContentReadbackHandler.initNativeContentReadbackHandler(); 162 if (mDelayedSurfaceRunnableList != null) { 163 nativeSurfaceCreated(mNativeContentViewRenderView); 164 for (int i = 0; i < mDelayedSurfaceRunnableList.size(); i++) { 165 mDelayedSurfaceRunnableList.get(i).run(); 166 } 167 mDelayedSurfaceRunnableList = null; 168 } 169 } 170 171 /** 172 * @return The content readback handler. 173 */ 174 public ContentReadbackHandler getContentReadbackHandler() { 175 return mContentReadbackHandler; 176 } 177 178 /** 179 * Sets the background color of the surface view. This method is necessary because the 180 * background color of ContentViewRenderView itself is covered by the background of 181 * SurfaceView. 182 * @param color The color of the background. 183 */ 184 public void setSurfaceViewBackgroundColor(int color) { 185 if (mSurfaceView != null) { 186 mSurfaceView.setBackgroundColor(color); 187 } 188 } 189 190 /** 191 * Should be called when the ContentViewRenderView is not needed anymore so its associated 192 * native resource can be freed. 193 */ 194 public void destroy() { 195 mContentReadbackHandler.destroy(); 196 mContentReadbackHandler = null; 197 mSurfaceView.getHolder().removeCallback(mSurfaceCallback); 198 nativeDestroy(mNativeContentViewRenderView); 199 mNativeContentViewRenderView = 0; 200 } 201 202 public void setCurrentContentViewCore(ContentViewCore contentViewCore) { 203 assert mNativeContentViewRenderView != 0; 204 mContentViewCore = contentViewCore; 205 206 if (mContentViewCore != null) { 207 mContentViewCore.onPhysicalBackingSizeChanged(getWidth(), getHeight()); 208 nativeSetCurrentContentViewCore(mNativeContentViewRenderView, 209 mContentViewCore.getNativeContentViewCore()); 210 } else { 211 nativeSetCurrentContentViewCore(mNativeContentViewRenderView, 0); 212 } 213 } 214 215 /** 216 * This method should be subclassed to provide actions to be performed once the view is ready to 217 * render. 218 */ 219 protected void onReadyToRender() { 220 } 221 222 /** 223 * This method could be subclassed optionally to provide a custom SurfaceView object to 224 * this ContentViewRenderView. 225 * @param context The context used to create the SurfaceView object. 226 * @return The created SurfaceView object. 227 */ 228 protected SurfaceView createSurfaceView(Context context) { 229 return new SurfaceView(context); 230 } 231 232 /** 233 * @return whether the surface view is initialized and ready to render. 234 */ 235 public boolean isInitialized() { 236 return mSurfaceView.getHolder().getSurface() != null; 237 } 238 239 /** 240 * Enter or leave overlay video mode. 241 * @param enabled Whether overlay mode is enabled. 242 */ 243 public void setOverlayVideoMode(boolean enabled) { 244 int format = enabled ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 245 mSurfaceView.getHolder().setFormat(format); 246 nativeSetOverlayVideoMode(mNativeContentViewRenderView, enabled); 247 } 248 249 /** 250 * Set the native layer tree helper for this {@link ContentViewRenderView}. 251 * @param layerTreeBuildHelperNativePtr Native pointer to the layer tree build helper. 252 */ 253 public void setLayerTreeBuildHelper(long layerTreeBuildHelperNativePtr) { 254 nativeSetLayerTreeBuildHelper(mNativeContentViewRenderView, layerTreeBuildHelperNativePtr); 255 } 256 257 @CalledByNative 258 protected void onCompositorLayout() { 259 } 260 261 @CalledByNative 262 private void onSwapBuffersCompleted() { 263 if (mSurfaceView.getBackground() != null) { 264 post(new Runnable() { 265 @Override public void run() { 266 mSurfaceView.setBackgroundResource(0); 267 } 268 }); 269 } 270 } 271 272 private native long nativeInit(long rootWindowNativePointer); 273 private native void nativeDestroy(long nativeContentViewRenderView); 274 private native void nativeSetCurrentContentViewCore(long nativeContentViewRenderView, 275 long nativeContentViewCore); 276 private native void nativeSetLayerTreeBuildHelper(long nativeContentViewRenderView, 277 long buildHelperNativePtr); 278 private native void nativeSurfaceCreated(long nativeContentViewRenderView); 279 private native void nativeSurfaceDestroyed(long nativeContentViewRenderView); 280 private native void nativeSurfaceChanged(long nativeContentViewRenderView, 281 int format, int width, int height, Surface surface); 282 private native void nativeSetOverlayVideoMode(long nativeContentViewRenderView, 283 boolean enabled); 284} 285