ContentViewRenderView.java revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright (c) 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.os.Build; 9import android.view.Surface; 10import android.view.SurfaceView; 11import android.view.SurfaceHolder; 12import android.widget.FrameLayout; 13 14import org.chromium.base.JNINamespace; 15 16/*** 17 * This view is used by a ContentView to render its content. 18 * Call {@link #setCurrentContentView(ContentView)} with the contentView that should be displayed. 19 * Note that only one ContentView can be shown at a time. 20 */ 21@JNINamespace("content") 22public class ContentViewRenderView extends FrameLayout { 23 24 // The native side of this object. 25 private int mNativeContentViewRenderView = 0; 26 private final SurfaceHolder.Callback mSurfaceCallback; 27 28 private SurfaceView mSurfaceView; 29 private VSyncAdapter mVSyncAdapter; 30 31 private ContentView mCurrentContentView; 32 33 /** 34 * Constructs a new ContentViewRenderView that should be can to a view hierarchy. 35 * Native code should add/remove the layers to be rendered through the ContentViewLayerRenderer. 36 * @param context The context used to create this. 37 */ 38 public ContentViewRenderView(Context context) { 39 super(context); 40 41 mNativeContentViewRenderView = nativeInit(); 42 assert mNativeContentViewRenderView != 0; 43 44 mSurfaceView = createSurfaceView(getContext()); 45 mSurfaceCallback = new SurfaceHolder.Callback() { 46 @Override 47 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 48 assert mNativeContentViewRenderView != 0; 49 nativeSurfaceSetSize(mNativeContentViewRenderView, width, height); 50 if (mCurrentContentView != null) { 51 mCurrentContentView.getContentViewCore().onPhysicalBackingSizeChanged( 52 width, height); 53 } 54 } 55 56 @Override 57 public void surfaceCreated(SurfaceHolder holder) { 58 assert mNativeContentViewRenderView != 0; 59 nativeSurfaceCreated(mNativeContentViewRenderView, holder.getSurface()); 60 onReadyToRender(); 61 } 62 63 @Override 64 public void surfaceDestroyed(SurfaceHolder holder) { 65 assert mNativeContentViewRenderView != 0; 66 nativeSurfaceDestroyed(mNativeContentViewRenderView); 67 } 68 }; 69 mSurfaceView.getHolder().addCallback(mSurfaceCallback); 70 71 mVSyncAdapter = new VSyncAdapter(getContext()); 72 addView(mSurfaceView, 73 new FrameLayout.LayoutParams( 74 FrameLayout.LayoutParams.MATCH_PARENT, 75 FrameLayout.LayoutParams.MATCH_PARENT)); 76 } 77 78 private static class VSyncAdapter implements VSyncManager.Provider, VSyncMonitor.Listener { 79 private final VSyncMonitor mVSyncMonitor; 80 private boolean mVSyncNotificationEnabled; 81 private VSyncManager.Listener mVSyncListener; 82 83 // The VSyncMonitor gives the timebase for the actual vsync, but we don't want render until 84 // we have had a chance for input events to propagate to the compositor thread. This takes 85 // 3 ms typically, so we adjust the vsync timestamps forward by a bit to give input events a 86 // chance to arrive. 87 private static final long INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS = 3200; 88 89 VSyncAdapter(Context context) { 90 mVSyncMonitor = new VSyncMonitor(context, this); 91 } 92 93 @Override 94 public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) { 95 if (mVSyncListener == null) return; 96 if (mVSyncNotificationEnabled) { 97 mVSyncListener.onVSync(vsyncTimeMicros); 98 mVSyncMonitor.requestUpdate(); 99 } else { 100 // Compensate for input event lag. Input events are delivered immediately on 101 // pre-JB releases, so this adjustment is only done for later versions. 102 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 103 vsyncTimeMicros += INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS; 104 } 105 mVSyncListener.updateVSync(vsyncTimeMicros, 106 mVSyncMonitor.getVSyncPeriodInMicroseconds()); 107 } 108 } 109 110 @Override 111 public void registerVSyncListener(VSyncManager.Listener listener) { 112 if (!mVSyncNotificationEnabled) mVSyncMonitor.requestUpdate(); 113 mVSyncNotificationEnabled = true; 114 } 115 116 @Override 117 public void unregisterVSyncListener(VSyncManager.Listener listener) { 118 mVSyncNotificationEnabled = false; 119 } 120 121 void setVSyncListener(VSyncManager.Listener listener) { 122 mVSyncListener = listener; 123 if (mVSyncListener != null) mVSyncMonitor.requestUpdate(); 124 } 125 } 126 127 /** 128 * Should be called when the ContentViewRenderView is not needed anymore so its associated 129 * native resource can be freed. 130 */ 131 public void destroy() { 132 mSurfaceView.getHolder().removeCallback(mSurfaceCallback); 133 nativeDestroy(mNativeContentViewRenderView); 134 mNativeContentViewRenderView = 0; 135 } 136 137 /** 138 * Makes the passed ContentView the one displayed by this ContentViewRenderView. 139 */ 140 public void setCurrentContentView(ContentView contentView) { 141 assert mNativeContentViewRenderView != 0; 142 ContentViewCore contentViewCore = contentView.getContentViewCore(); 143 nativeSetCurrentContentView(mNativeContentViewRenderView, 144 contentViewCore.getNativeContentViewCore()); 145 146 mCurrentContentView = contentView; 147 contentViewCore.onPhysicalBackingSizeChanged(getWidth(), getHeight()); 148 mVSyncAdapter.setVSyncListener(contentViewCore.getVSyncListener(mVSyncAdapter)); 149 } 150 151 /** 152 * This method should be subclassed to provide actions to be performed once the view is ready to 153 * render. 154 */ 155 protected void onReadyToRender() { 156 } 157 158 /** 159 * This method could be subclassed optionally to provide a custom SurfaceView object to 160 * this ContentViewRenderView. 161 * @param context The context used to create the SurfaceView object. 162 * @return The created SurfaceView object. 163 */ 164 protected SurfaceView createSurfaceView(Context context) { 165 return new SurfaceView(context); 166 } 167 168 /** 169 * @return whether the surface view is initialized and ready to render. 170 */ 171 public boolean isInitialized() { 172 return mSurfaceView.getHolder().getSurface() != null; 173 } 174 175 private static native int nativeInit(); 176 private native void nativeDestroy(int nativeContentViewRenderView); 177 private native void nativeSetCurrentContentView(int nativeContentViewRenderView, 178 int nativeContentView); 179 private native void nativeSurfaceCreated(int nativeContentViewRenderView, Surface surface); 180 private native void nativeSurfaceDestroyed(int nativeContentViewRenderView); 181 private native void nativeSurfaceSetSize(int nativeContentViewRenderView, 182 int width, int height); 183} 184