Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2006 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 android.view;
     18 
     19 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
     20 import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
     21 import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
     22 import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
     23 
     24 import android.content.Context;
     25 import android.content.res.CompatibilityInfo.Translator;
     26 import android.content.res.Configuration;
     27 import android.graphics.Canvas;
     28 import android.graphics.PixelFormat;
     29 import android.graphics.PorterDuff;
     30 import android.graphics.Rect;
     31 import android.graphics.Region;
     32 import android.os.Build;
     33 import android.os.Handler;
     34 import android.os.IBinder;
     35 import android.os.Looper;
     36 import android.os.SystemClock;
     37 import android.util.AttributeSet;
     38 import android.util.Log;
     39 
     40 import com.android.internal.view.SurfaceCallbackHelper;
     41 
     42 import java.util.ArrayList;
     43 import java.util.concurrent.locks.ReentrantLock;
     44 
     45 /**
     46  * Provides a dedicated drawing surface embedded inside of a view hierarchy.
     47  * You can control the format of this surface and, if you like, its size; the
     48  * SurfaceView takes care of placing the surface at the correct location on the
     49  * screen
     50  *
     51  * <p>The surface is Z ordered so that it is behind the window holding its
     52  * SurfaceView; the SurfaceView punches a hole in its window to allow its
     53  * surface to be displayed. The view hierarchy will take care of correctly
     54  * compositing with the Surface any siblings of the SurfaceView that would
     55  * normally appear on top of it. This can be used to place overlays such as
     56  * buttons on top of the Surface, though note however that it can have an
     57  * impact on performance since a full alpha-blended composite will be performed
     58  * each time the Surface changes.
     59  *
     60  * <p> The transparent region that makes the surface visible is based on the
     61  * layout positions in the view hierarchy. If the post-layout transform
     62  * properties are used to draw a sibling view on top of the SurfaceView, the
     63  * view may not be properly composited with the surface.
     64  *
     65  * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
     66  * which can be retrieved by calling {@link #getHolder}.
     67  *
     68  * <p>The Surface will be created for you while the SurfaceView's window is
     69  * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
     70  * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
     71  * Surface is created and destroyed as the window is shown and hidden.
     72  *
     73  * <p>One of the purposes of this class is to provide a surface in which a
     74  * secondary thread can render into the screen. If you are going to use it
     75  * this way, you need to be aware of some threading semantics:
     76  *
     77  * <ul>
     78  * <li> All SurfaceView and
     79  * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
     80  * from the thread running the SurfaceView's window (typically the main thread
     81  * of the application). They thus need to correctly synchronize with any
     82  * state that is also touched by the drawing thread.
     83  * <li> You must ensure that the drawing thread only touches the underlying
     84  * Surface while it is valid -- between
     85  * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
     86  * and
     87  * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
     88  * </ul>
     89  *
     90  * <p class="note"><strong>Note:</strong> Starting in platform version
     91  * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
     92  * updated synchronously with other View rendering. This means that translating
     93  * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
     94  * artifacts may occur on previous versions of the platform when its window is
     95  * positioned asynchronously.</p>
     96  */
     97 public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
     98     private static final String TAG = "SurfaceView";
     99     private static final boolean DEBUG = false;
    100 
    101     final ArrayList<SurfaceHolder.Callback> mCallbacks
    102             = new ArrayList<SurfaceHolder.Callback>();
    103 
    104     final int[] mLocation = new int[2];
    105 
    106     final ReentrantLock mSurfaceLock = new ReentrantLock();
    107     final Surface mSurface = new Surface();       // Current surface in use
    108     boolean mDrawingStopped = true;
    109     // We use this to track if the application has produced a frame
    110     // in to the Surface. Up until that point, we should be careful not to punch
    111     // holes.
    112     boolean mDrawFinished = false;
    113 
    114     final Rect mScreenRect = new Rect();
    115     SurfaceSession mSurfaceSession;
    116 
    117     SurfaceControl mSurfaceControl;
    118     // In the case of format changes we switch out the surface in-place
    119     // we need to preserve the old one until the new one has drawn.
    120     SurfaceControl mDeferredDestroySurfaceControl;
    121     final Rect mTmpRect = new Rect();
    122     final Configuration mConfiguration = new Configuration();
    123 
    124     int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
    125 
    126     boolean mIsCreating = false;
    127     private volatile boolean mRtHandlingPositionUpdates = false;
    128 
    129     private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
    130             = new ViewTreeObserver.OnScrollChangedListener() {
    131                     @Override
    132                     public void onScrollChanged() {
    133                         updateSurface();
    134                     }
    135             };
    136 
    137     private final ViewTreeObserver.OnPreDrawListener mDrawListener =
    138             new ViewTreeObserver.OnPreDrawListener() {
    139                 @Override
    140                 public boolean onPreDraw() {
    141                     // reposition ourselves where the surface is
    142                     mHaveFrame = getWidth() > 0 && getHeight() > 0;
    143                     updateSurface();
    144                     return true;
    145                 }
    146             };
    147 
    148     boolean mRequestedVisible = false;
    149     boolean mWindowVisibility = false;
    150     boolean mLastWindowVisibility = false;
    151     boolean mViewVisibility = false;
    152     boolean mWindowStopped = false;
    153 
    154     int mRequestedWidth = -1;
    155     int mRequestedHeight = -1;
    156     /* Set SurfaceView's format to 565 by default to maintain backward
    157      * compatibility with applications assuming this format.
    158      */
    159     int mRequestedFormat = PixelFormat.RGB_565;
    160 
    161     boolean mHaveFrame = false;
    162     boolean mSurfaceCreated = false;
    163     long mLastLockTime = 0;
    164 
    165     boolean mVisible = false;
    166     int mWindowSpaceLeft = -1;
    167     int mWindowSpaceTop = -1;
    168     int mSurfaceWidth = -1;
    169     int mSurfaceHeight = -1;
    170     int mFormat = -1;
    171     final Rect mSurfaceFrame = new Rect();
    172     int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
    173     private Translator mTranslator;
    174 
    175     private boolean mGlobalListenersAdded;
    176     private boolean mAttachedToWindow;
    177 
    178     private int mSurfaceFlags = SurfaceControl.HIDDEN;
    179 
    180     private int mPendingReportDraws;
    181 
    182     public SurfaceView(Context context) {
    183         this(context, null);
    184     }
    185 
    186     public SurfaceView(Context context, AttributeSet attrs) {
    187         this(context, attrs, 0);
    188     }
    189 
    190     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
    191         this(context, attrs, defStyleAttr, 0);
    192     }
    193 
    194     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    195         super(context, attrs, defStyleAttr, defStyleRes);
    196         mRenderNode.requestPositionUpdates(this);
    197 
    198         setWillNotDraw(true);
    199     }
    200 
    201     /**
    202      * Return the SurfaceHolder providing access and control over this
    203      * SurfaceView's underlying surface.
    204      *
    205      * @return SurfaceHolder The holder of the surface.
    206      */
    207     public SurfaceHolder getHolder() {
    208         return mSurfaceHolder;
    209     }
    210 
    211     private void updateRequestedVisibility() {
    212         mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
    213     }
    214 
    215     /** @hide */
    216     @Override
    217     public void windowStopped(boolean stopped) {
    218         mWindowStopped = stopped;
    219         updateRequestedVisibility();
    220         updateSurface();
    221     }
    222 
    223     @Override
    224     protected void onAttachedToWindow() {
    225         super.onAttachedToWindow();
    226 
    227         getViewRootImpl().addWindowStoppedCallback(this);
    228         mWindowStopped = false;
    229 
    230         mViewVisibility = getVisibility() == VISIBLE;
    231         updateRequestedVisibility();
    232 
    233         mAttachedToWindow = true;
    234         mParent.requestTransparentRegion(SurfaceView.this);
    235         if (!mGlobalListenersAdded) {
    236             ViewTreeObserver observer = getViewTreeObserver();
    237             observer.addOnScrollChangedListener(mScrollChangedListener);
    238             observer.addOnPreDrawListener(mDrawListener);
    239             mGlobalListenersAdded = true;
    240         }
    241     }
    242 
    243     @Override
    244     protected void onWindowVisibilityChanged(int visibility) {
    245         super.onWindowVisibilityChanged(visibility);
    246         mWindowVisibility = visibility == VISIBLE;
    247         updateRequestedVisibility();
    248         updateSurface();
    249     }
    250 
    251     @Override
    252     public void setVisibility(int visibility) {
    253         super.setVisibility(visibility);
    254         mViewVisibility = visibility == VISIBLE;
    255         boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
    256         if (newRequestedVisible != mRequestedVisible) {
    257             // our base class (View) invalidates the layout only when
    258             // we go from/to the GONE state. However, SurfaceView needs
    259             // to request a re-layout when the visibility changes at all.
    260             // This is needed because the transparent region is computed
    261             // as part of the layout phase, and it changes (obviously) when
    262             // the visibility changes.
    263             requestLayout();
    264         }
    265         mRequestedVisible = newRequestedVisible;
    266         updateSurface();
    267     }
    268 
    269     private void performDrawFinished() {
    270         if (mPendingReportDraws > 0) {
    271             mDrawFinished = true;
    272             if (mAttachedToWindow) {
    273                 notifyDrawFinished();
    274                 invalidate();
    275             }
    276         } else {
    277             Log.e(TAG, System.identityHashCode(this) + "finished drawing"
    278                     + " but no pending report draw (extra call"
    279                     + " to draw completion runnable?)");
    280         }
    281     }
    282 
    283     void notifyDrawFinished() {
    284         ViewRootImpl viewRoot = getViewRootImpl();
    285         if (viewRoot != null) {
    286             viewRoot.pendingDrawFinished();
    287         }
    288         mPendingReportDraws--;
    289     }
    290 
    291     @Override
    292     protected void onDetachedFromWindow() {
    293         ViewRootImpl viewRoot = getViewRootImpl();
    294         // It's possible to create a SurfaceView using the default constructor and never
    295         // attach it to a view hierarchy, this is a common use case when dealing with
    296         // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
    297         // the lifecycle. Instead of attaching it to a view, he/she can just pass
    298         // the SurfaceHolder forward, most live wallpapers do it.
    299         if (viewRoot != null) {
    300             viewRoot.removeWindowStoppedCallback(this);
    301         }
    302 
    303         mAttachedToWindow = false;
    304         if (mGlobalListenersAdded) {
    305             ViewTreeObserver observer = getViewTreeObserver();
    306             observer.removeOnScrollChangedListener(mScrollChangedListener);
    307             observer.removeOnPreDrawListener(mDrawListener);
    308             mGlobalListenersAdded = false;
    309         }
    310 
    311         while (mPendingReportDraws > 0) {
    312             notifyDrawFinished();
    313         }
    314 
    315         mRequestedVisible = false;
    316 
    317         updateSurface();
    318         if (mSurfaceControl != null) {
    319             mSurfaceControl.destroy();
    320         }
    321         mSurfaceControl = null;
    322 
    323         mHaveFrame = false;
    324 
    325         super.onDetachedFromWindow();
    326     }
    327 
    328     @Override
    329     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    330         int width = mRequestedWidth >= 0
    331                 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
    332                 : getDefaultSize(0, widthMeasureSpec);
    333         int height = mRequestedHeight >= 0
    334                 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
    335                 : getDefaultSize(0, heightMeasureSpec);
    336         setMeasuredDimension(width, height);
    337     }
    338 
    339     /** @hide */
    340     @Override
    341     protected boolean setFrame(int left, int top, int right, int bottom) {
    342         boolean result = super.setFrame(left, top, right, bottom);
    343         updateSurface();
    344         return result;
    345     }
    346 
    347     @Override
    348     public boolean gatherTransparentRegion(Region region) {
    349         if (isAboveParent() || !mDrawFinished) {
    350             return super.gatherTransparentRegion(region);
    351         }
    352 
    353         boolean opaque = true;
    354         if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
    355             // this view draws, remove it from the transparent region
    356             opaque = super.gatherTransparentRegion(region);
    357         } else if (region != null) {
    358             int w = getWidth();
    359             int h = getHeight();
    360             if (w>0 && h>0) {
    361                 getLocationInWindow(mLocation);
    362                 // otherwise, punch a hole in the whole hierarchy
    363                 int l = mLocation[0];
    364                 int t = mLocation[1];
    365                 region.op(l, t, l+w, t+h, Region.Op.UNION);
    366             }
    367         }
    368         if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
    369             opaque = false;
    370         }
    371         return opaque;
    372     }
    373 
    374     @Override
    375     public void draw(Canvas canvas) {
    376         if (mDrawFinished && !isAboveParent()) {
    377             // draw() is not called when SKIP_DRAW is set
    378             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
    379                 // punch a whole in the view-hierarchy below us
    380                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
    381             }
    382         }
    383         super.draw(canvas);
    384     }
    385 
    386     @Override
    387     protected void dispatchDraw(Canvas canvas) {
    388         if (mDrawFinished && !isAboveParent()) {
    389             // draw() is not called when SKIP_DRAW is set
    390             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
    391                 // punch a whole in the view-hierarchy below us
    392                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
    393             }
    394         }
    395         super.dispatchDraw(canvas);
    396     }
    397 
    398     /**
    399      * Control whether the surface view's surface is placed on top of another
    400      * regular surface view in the window (but still behind the window itself).
    401      * This is typically used to place overlays on top of an underlying media
    402      * surface view.
    403      *
    404      * <p>Note that this must be set before the surface view's containing
    405      * window is attached to the window manager.
    406      *
    407      * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
    408      */
    409     public void setZOrderMediaOverlay(boolean isMediaOverlay) {
    410         mSubLayer = isMediaOverlay
    411             ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
    412     }
    413 
    414     /**
    415      * Control whether the surface view's surface is placed on top of its
    416      * window.  Normally it is placed behind the window, to allow it to
    417      * (for the most part) appear to composite with the views in the
    418      * hierarchy.  By setting this, you cause it to be placed above the
    419      * window.  This means that none of the contents of the window this
    420      * SurfaceView is in will be visible on top of its surface.
    421      *
    422      * <p>Note that this must be set before the surface view's containing
    423      * window is attached to the window manager.
    424      *
    425      * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
    426      */
    427     public void setZOrderOnTop(boolean onTop) {
    428         if (onTop) {
    429             mSubLayer = APPLICATION_PANEL_SUBLAYER;
    430         } else {
    431             mSubLayer = APPLICATION_MEDIA_SUBLAYER;
    432         }
    433     }
    434 
    435     /**
    436      * Control whether the surface view's content should be treated as secure,
    437      * preventing it from appearing in screenshots or from being viewed on
    438      * non-secure displays.
    439      *
    440      * <p>Note that this must be set before the surface view's containing
    441      * window is attached to the window manager.
    442      *
    443      * <p>See {@link android.view.Display#FLAG_SECURE} for details.
    444      *
    445      * @param isSecure True if the surface view is secure.
    446      */
    447     public void setSecure(boolean isSecure) {
    448         if (isSecure) {
    449             mSurfaceFlags |= SurfaceControl.SECURE;
    450         } else {
    451             mSurfaceFlags &= ~SurfaceControl.SECURE;
    452         }
    453     }
    454 
    455     private void updateOpaqueFlag() {
    456         if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
    457             mSurfaceFlags |= SurfaceControl.OPAQUE;
    458         } else {
    459             mSurfaceFlags &= ~SurfaceControl.OPAQUE;
    460         }
    461     }
    462 
    463     private Rect getParentSurfaceInsets() {
    464         final ViewRootImpl root = getViewRootImpl();
    465         if (root == null) {
    466             return null;
    467         } else {
    468             return root.mWindowAttributes.surfaceInsets;
    469         }
    470     }
    471 
    472     /** @hide */
    473     protected void updateSurface() {
    474         if (!mHaveFrame) {
    475             return;
    476         }
    477         ViewRootImpl viewRoot = getViewRootImpl();
    478         if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
    479             return;
    480         }
    481 
    482         mTranslator = viewRoot.mTranslator;
    483         if (mTranslator != null) {
    484             mSurface.setCompatibilityTranslator(mTranslator);
    485         }
    486 
    487         int myWidth = mRequestedWidth;
    488         if (myWidth <= 0) myWidth = getWidth();
    489         int myHeight = mRequestedHeight;
    490         if (myHeight <= 0) myHeight = getHeight();
    491 
    492         final boolean formatChanged = mFormat != mRequestedFormat;
    493         final boolean visibleChanged = mVisible != mRequestedVisible;
    494         final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
    495                 && mRequestedVisible;
    496         final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
    497         final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
    498         boolean redrawNeeded = false;
    499 
    500         if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
    501             getLocationInWindow(mLocation);
    502 
    503             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
    504                     + "Changes: creating=" + creating
    505                     + " format=" + formatChanged + " size=" + sizeChanged
    506                     + " visible=" + visibleChanged
    507                     + " left=" + (mWindowSpaceLeft != mLocation[0])
    508                     + " top=" + (mWindowSpaceTop != mLocation[1]));
    509 
    510             try {
    511                 final boolean visible = mVisible = mRequestedVisible;
    512                 mWindowSpaceLeft = mLocation[0];
    513                 mWindowSpaceTop = mLocation[1];
    514                 mSurfaceWidth = myWidth;
    515                 mSurfaceHeight = myHeight;
    516                 mFormat = mRequestedFormat;
    517                 mLastWindowVisibility = mWindowVisibility;
    518 
    519                 mScreenRect.left = mWindowSpaceLeft;
    520                 mScreenRect.top = mWindowSpaceTop;
    521                 mScreenRect.right = mWindowSpaceLeft + getWidth();
    522                 mScreenRect.bottom = mWindowSpaceTop + getHeight();
    523                 if (mTranslator != null) {
    524                     mTranslator.translateRectInAppWindowToScreen(mScreenRect);
    525                 }
    526 
    527                 final Rect surfaceInsets = getParentSurfaceInsets();
    528                 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
    529 
    530                 if (creating) {
    531                     mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
    532                     mDeferredDestroySurfaceControl = mSurfaceControl;
    533 
    534                     updateOpaqueFlag();
    535                     mSurfaceControl = new SurfaceControlWithBackground(mSurfaceSession,
    536                             "SurfaceView - " + viewRoot.getTitle().toString(),
    537                             mSurfaceWidth, mSurfaceHeight, mFormat,
    538                             mSurfaceFlags);
    539                 } else if (mSurfaceControl == null) {
    540                     return;
    541                 }
    542 
    543                 boolean realSizeChanged = false;
    544 
    545                 mSurfaceLock.lock();
    546                 try {
    547                     mDrawingStopped = !visible;
    548 
    549                     if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
    550                             + "Cur surface: " + mSurface);
    551 
    552                     SurfaceControl.openTransaction();
    553                     try {
    554                         mSurfaceControl.setLayer(mSubLayer);
    555                         if (mViewVisibility) {
    556                             mSurfaceControl.show();
    557                         } else {
    558                             mSurfaceControl.hide();
    559                         }
    560 
    561                         // While creating the surface, we will set it's initial
    562                         // geometry. Outside of that though, we should generally
    563                         // leave it to the RenderThread.
    564                         //
    565                         // There is one more case when the buffer size changes we aren't yet
    566                         // prepared to sync (as even following the transaction applying
    567                         // we still need to latch a buffer).
    568                         // b/28866173
    569                         if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
    570                             mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
    571                             mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
    572                                     0.0f, 0.0f,
    573                                     mScreenRect.height() / (float) mSurfaceHeight);
    574                         }
    575                         if (sizeChanged) {
    576                             mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
    577                         }
    578                     } finally {
    579                         SurfaceControl.closeTransaction();
    580                     }
    581 
    582                     if (sizeChanged || creating) {
    583                         redrawNeeded = true;
    584                     }
    585 
    586                     mSurfaceFrame.left = 0;
    587                     mSurfaceFrame.top = 0;
    588                     if (mTranslator == null) {
    589                         mSurfaceFrame.right = mSurfaceWidth;
    590                         mSurfaceFrame.bottom = mSurfaceHeight;
    591                     } else {
    592                         float appInvertedScale = mTranslator.applicationInvertedScale;
    593                         mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
    594                         mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
    595                     }
    596 
    597                     final int surfaceWidth = mSurfaceFrame.right;
    598                     final int surfaceHeight = mSurfaceFrame.bottom;
    599                     realSizeChanged = mLastSurfaceWidth != surfaceWidth
    600                             || mLastSurfaceHeight != surfaceHeight;
    601                     mLastSurfaceWidth = surfaceWidth;
    602                     mLastSurfaceHeight = surfaceHeight;
    603                 } finally {
    604                     mSurfaceLock.unlock();
    605                 }
    606 
    607                 try {
    608                     redrawNeeded |= visible && !mDrawFinished;
    609 
    610                     SurfaceHolder.Callback callbacks[] = null;
    611 
    612                     final boolean surfaceChanged = creating;
    613                     if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
    614                         mSurfaceCreated = false;
    615                         if (mSurface.isValid()) {
    616                             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
    617                                     + "visibleChanged -- surfaceDestroyed");
    618                             callbacks = getSurfaceCallbacks();
    619                             for (SurfaceHolder.Callback c : callbacks) {
    620                                 c.surfaceDestroyed(mSurfaceHolder);
    621                             }
    622                             // Since Android N the same surface may be reused and given to us
    623                             // again by the system server at a later point. However
    624                             // as we didn't do this in previous releases, clients weren't
    625                             // necessarily required to clean up properly in
    626                             // surfaceDestroyed. This leads to problems for example when
    627                             // clients don't destroy their EGL context, and try
    628                             // and create a new one on the same surface following reuse.
    629                             // Since there is no valid use of the surface in-between
    630                             // surfaceDestroyed and surfaceCreated, we force a disconnect,
    631                             // so the next connect will always work if we end up reusing
    632                             // the surface.
    633                             if (mSurface.isValid()) {
    634                                 mSurface.forceScopedDisconnect();
    635                             }
    636                         }
    637                     }
    638 
    639                     if (creating) {
    640                         mSurface.copyFrom(mSurfaceControl);
    641                     }
    642 
    643                     if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
    644                             < Build.VERSION_CODES.O) {
    645                         // Some legacy applications use the underlying native {@link Surface} object
    646                         // as a key to whether anything has changed. In these cases, updates to the
    647                         // existing {@link Surface} will be ignored when the size changes.
    648                         // Therefore, we must explicitly recreate the {@link Surface} in these
    649                         // cases.
    650                         mSurface.createFrom(mSurfaceControl);
    651                     }
    652 
    653                     if (visible && mSurface.isValid()) {
    654                         if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
    655                             mSurfaceCreated = true;
    656                             mIsCreating = true;
    657                             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
    658                                     + "visibleChanged -- surfaceCreated");
    659                             if (callbacks == null) {
    660                                 callbacks = getSurfaceCallbacks();
    661                             }
    662                             for (SurfaceHolder.Callback c : callbacks) {
    663                                 c.surfaceCreated(mSurfaceHolder);
    664                             }
    665                         }
    666                         if (creating || formatChanged || sizeChanged
    667                                 || visibleChanged || realSizeChanged) {
    668                             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
    669                                     + "surfaceChanged -- format=" + mFormat
    670                                     + " w=" + myWidth + " h=" + myHeight);
    671                             if (callbacks == null) {
    672                                 callbacks = getSurfaceCallbacks();
    673                             }
    674                             for (SurfaceHolder.Callback c : callbacks) {
    675                                 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
    676                             }
    677                         }
    678                         if (redrawNeeded) {
    679                             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
    680                                     + "surfaceRedrawNeeded");
    681                             if (callbacks == null) {
    682                                 callbacks = getSurfaceCallbacks();
    683                             }
    684 
    685                             mPendingReportDraws++;
    686                             viewRoot.drawPending();
    687                             SurfaceCallbackHelper sch =
    688                                     new SurfaceCallbackHelper(this::onDrawFinished);
    689                             sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
    690                         }
    691                     }
    692                 } finally {
    693                     mIsCreating = false;
    694                     if (mSurfaceControl != null && !mSurfaceCreated) {
    695                         mSurface.release();
    696                         // If we are not in the stopped state, then the destruction of the Surface
    697                         // represents a visual change we need to display, and we should go ahead
    698                         // and destroy the SurfaceControl. However if we are in the stopped state,
    699                         // we can just leave the Surface around so it can be a part of animations,
    700                         // and we let the life-time be tied to the parent surface.
    701                         if (!mWindowStopped) {
    702                             mSurfaceControl.destroy();
    703                             mSurfaceControl = null;
    704                         }
    705                     }
    706                 }
    707             } catch (Exception ex) {
    708                 Log.e(TAG, "Exception configuring surface", ex);
    709             }
    710             if (DEBUG) Log.v(
    711                 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
    712                 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
    713                 + ", frame=" + mSurfaceFrame);
    714         } else {
    715             // Calculate the window position in case RT loses the window
    716             // and we need to fallback to a UI-thread driven position update
    717             getLocationInSurface(mLocation);
    718             final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
    719                     || mWindowSpaceTop != mLocation[1];
    720             final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
    721                     || getHeight() != mScreenRect.height();
    722             if (positionChanged || layoutSizeChanged) { // Only the position has changed
    723                 mWindowSpaceLeft = mLocation[0];
    724                 mWindowSpaceTop = mLocation[1];
    725                 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
    726                 // in view local space.
    727                 mLocation[0] = getWidth();
    728                 mLocation[1] = getHeight();
    729 
    730                 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
    731                         mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
    732 
    733                 if (mTranslator != null) {
    734                     mTranslator.translateRectInAppWindowToScreen(mScreenRect);
    735                 }
    736 
    737                 if (mSurfaceControl == null) {
    738                     return;
    739                 }
    740 
    741                 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
    742                     try {
    743                         if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
    744                                 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    745                                 mScreenRect.left, mScreenRect.top,
    746                                 mScreenRect.right, mScreenRect.bottom));
    747                         setParentSpaceRectangle(mScreenRect, -1);
    748                     } catch (Exception ex) {
    749                         Log.e(TAG, "Exception configuring surface", ex);
    750                     }
    751                 }
    752             }
    753         }
    754     }
    755 
    756     private void onDrawFinished() {
    757         if (DEBUG) {
    758             Log.i(TAG, System.identityHashCode(this) + " "
    759                     + "finishedDrawing");
    760         }
    761 
    762         if (mDeferredDestroySurfaceControl != null) {
    763             mDeferredDestroySurfaceControl.destroy();
    764             mDeferredDestroySurfaceControl = null;
    765         }
    766 
    767         runOnUiThread(() -> {
    768             performDrawFinished();
    769         });
    770     }
    771 
    772     private void setParentSpaceRectangle(Rect position, long frameNumber) {
    773         ViewRootImpl viewRoot = getViewRootImpl();
    774 
    775         SurfaceControl.openTransaction();
    776         try {
    777             if (frameNumber > 0) {
    778                 mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
    779             }
    780             mSurfaceControl.setPosition(position.left, position.top);
    781             mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
    782                     0.0f, 0.0f,
    783                     position.height() / (float) mSurfaceHeight);
    784         } finally {
    785             SurfaceControl.closeTransaction();
    786         }
    787     }
    788 
    789     private Rect mRTLastReportedPosition = new Rect();
    790 
    791     /**
    792      * Called by native by a Rendering Worker thread to update the window position
    793      * @hide
    794      */
    795     public final void updateSurfacePosition_renderWorker(long frameNumber,
    796             int left, int top, int right, int bottom) {
    797         if (mSurfaceControl == null) {
    798             return;
    799         }
    800 
    801         // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
    802         // its 2nd frame if RenderThread is running slowly could potentially see
    803         // this as false, enter the branch, get pre-empted, then this comes along
    804         // and reports a new position, then the UI thread resumes and reports
    805         // its position. This could therefore be de-sync'd in that interval, but
    806         // the synchronization would violate the rule that RT must never block
    807         // on the UI thread which would open up potential deadlocks. The risk of
    808         // a single-frame desync is therefore preferable for now.
    809         mRtHandlingPositionUpdates = true;
    810         if (mRTLastReportedPosition.left == left
    811                 && mRTLastReportedPosition.top == top
    812                 && mRTLastReportedPosition.right == right
    813                 && mRTLastReportedPosition.bottom == bottom) {
    814             return;
    815         }
    816         try {
    817             if (DEBUG) {
    818                 Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
    819                         "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    820                         frameNumber, left, top, right, bottom));
    821             }
    822             mRTLastReportedPosition.set(left, top, right, bottom);
    823             setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
    824             // Now overwrite mRTLastReportedPosition with our values
    825         } catch (Exception ex) {
    826             Log.e(TAG, "Exception from repositionChild", ex);
    827         }
    828     }
    829 
    830     /**
    831      * Called by native on RenderThread to notify that the view is no longer in the
    832      * draw tree. UI thread is blocked at this point.
    833      * @hide
    834      */
    835     public final void surfacePositionLost_uiRtSync(long frameNumber) {
    836         if (DEBUG) {
    837             Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
    838                     System.identityHashCode(this), frameNumber));
    839         }
    840         mRTLastReportedPosition.setEmpty();
    841 
    842         if (mSurfaceControl == null) {
    843             return;
    844         }
    845         if (mRtHandlingPositionUpdates) {
    846             mRtHandlingPositionUpdates = false;
    847             // This callback will happen while the UI thread is blocked, so we can
    848             // safely access other member variables at this time.
    849             // So do what the UI thread would have done if RT wasn't handling position
    850             // updates.
    851             if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
    852                 try {
    853                     if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
    854                             "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    855                             mScreenRect.left, mScreenRect.top,
    856                             mScreenRect.right, mScreenRect.bottom));
    857                     setParentSpaceRectangle(mScreenRect, frameNumber);
    858                 } catch (Exception ex) {
    859                     Log.e(TAG, "Exception configuring surface", ex);
    860                 }
    861             }
    862         }
    863     }
    864 
    865     private SurfaceHolder.Callback[] getSurfaceCallbacks() {
    866         SurfaceHolder.Callback callbacks[];
    867         synchronized (mCallbacks) {
    868             callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
    869             mCallbacks.toArray(callbacks);
    870         }
    871         return callbacks;
    872     }
    873 
    874     /**
    875      * This method still exists only for compatibility reasons because some applications have relied
    876      * on this method via reflection. See Issue 36345857 for details.
    877      *
    878      * @deprecated No platform code is using this method anymore.
    879      * @hide
    880      */
    881     @Deprecated
    882     public void setWindowType(int type) {
    883         if (getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
    884             throw new UnsupportedOperationException(
    885                     "SurfaceView#setWindowType() has never been a public API.");
    886         }
    887 
    888         if (type == TYPE_APPLICATION_PANEL) {
    889             Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
    890                     + "just to make the SurfaceView to be placed on top of its window, you must "
    891                     + "call setZOrderOnTop(true) instead.", new Throwable());
    892             setZOrderOnTop(true);
    893             return;
    894         }
    895         Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
    896                 + "type=" + type, new Throwable());
    897     }
    898 
    899     private void runOnUiThread(Runnable runnable) {
    900         Handler handler = getHandler();
    901         if (handler != null && handler.getLooper() != Looper.myLooper()) {
    902             handler.post(runnable);
    903         } else {
    904             runnable.run();
    905         }
    906     }
    907 
    908     /**
    909      * Check to see if the surface has fixed size dimensions or if the surface's
    910      * dimensions are dimensions are dependent on its current layout.
    911      *
    912      * @return true if the surface has dimensions that are fixed in size
    913      * @hide
    914      */
    915     public boolean isFixedSize() {
    916         return (mRequestedWidth != -1 || mRequestedHeight != -1);
    917     }
    918 
    919     private boolean isAboveParent() {
    920         return mSubLayer >= 0;
    921     }
    922 
    923     private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
    924         private static final String LOG_TAG = "SurfaceHolder";
    925 
    926         @Override
    927         public boolean isCreating() {
    928             return mIsCreating;
    929         }
    930 
    931         @Override
    932         public void addCallback(Callback callback) {
    933             synchronized (mCallbacks) {
    934                 // This is a linear search, but in practice we'll
    935                 // have only a couple callbacks, so it doesn't matter.
    936                 if (mCallbacks.contains(callback) == false) {
    937                     mCallbacks.add(callback);
    938                 }
    939             }
    940         }
    941 
    942         @Override
    943         public void removeCallback(Callback callback) {
    944             synchronized (mCallbacks) {
    945                 mCallbacks.remove(callback);
    946             }
    947         }
    948 
    949         @Override
    950         public void setFixedSize(int width, int height) {
    951             if (mRequestedWidth != width || mRequestedHeight != height) {
    952                 mRequestedWidth = width;
    953                 mRequestedHeight = height;
    954                 requestLayout();
    955             }
    956         }
    957 
    958         @Override
    959         public void setSizeFromLayout() {
    960             if (mRequestedWidth != -1 || mRequestedHeight != -1) {
    961                 mRequestedWidth = mRequestedHeight = -1;
    962                 requestLayout();
    963             }
    964         }
    965 
    966         @Override
    967         public void setFormat(int format) {
    968             // for backward compatibility reason, OPAQUE always
    969             // means 565 for SurfaceView
    970             if (format == PixelFormat.OPAQUE)
    971                 format = PixelFormat.RGB_565;
    972 
    973             mRequestedFormat = format;
    974             if (mSurfaceControl != null) {
    975                 updateSurface();
    976             }
    977         }
    978 
    979         /**
    980          * @deprecated setType is now ignored.
    981          */
    982         @Override
    983         @Deprecated
    984         public void setType(int type) { }
    985 
    986         @Override
    987         public void setKeepScreenOn(boolean screenOn) {
    988             runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
    989         }
    990 
    991         /**
    992          * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
    993          *
    994          * After drawing into the provided {@link Canvas}, the caller must
    995          * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
    996          *
    997          * The caller must redraw the entire surface.
    998          * @return A canvas for drawing into the surface.
    999          */
   1000         @Override
   1001         public Canvas lockCanvas() {
   1002             return internalLockCanvas(null, false);
   1003         }
   1004 
   1005         /**
   1006          * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
   1007          *
   1008          * After drawing into the provided {@link Canvas}, the caller must
   1009          * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
   1010          *
   1011          * @param inOutDirty A rectangle that represents the dirty region that the caller wants
   1012          * to redraw.  This function may choose to expand the dirty rectangle if for example
   1013          * the surface has been resized or if the previous contents of the surface were
   1014          * not available.  The caller must redraw the entire dirty region as represented
   1015          * by the contents of the inOutDirty rectangle upon return from this function.
   1016          * The caller may also pass <code>null</code> instead, in the case where the
   1017          * entire surface should be redrawn.
   1018          * @return A canvas for drawing into the surface.
   1019          */
   1020         @Override
   1021         public Canvas lockCanvas(Rect inOutDirty) {
   1022             return internalLockCanvas(inOutDirty, false);
   1023         }
   1024 
   1025         @Override
   1026         public Canvas lockHardwareCanvas() {
   1027             return internalLockCanvas(null, true);
   1028         }
   1029 
   1030         private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
   1031             mSurfaceLock.lock();
   1032 
   1033             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
   1034                     + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
   1035 
   1036             Canvas c = null;
   1037             if (!mDrawingStopped && mSurfaceControl != null) {
   1038                 try {
   1039                     if (hardware) {
   1040                         c = mSurface.lockHardwareCanvas();
   1041                     } else {
   1042                         c = mSurface.lockCanvas(dirty);
   1043                     }
   1044                 } catch (Exception e) {
   1045                     Log.e(LOG_TAG, "Exception locking surface", e);
   1046                 }
   1047             }
   1048 
   1049             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
   1050             if (c != null) {
   1051                 mLastLockTime = SystemClock.uptimeMillis();
   1052                 return c;
   1053             }
   1054 
   1055             // If the Surface is not ready to be drawn, then return null,
   1056             // but throttle calls to this function so it isn't called more
   1057             // than every 100ms.
   1058             long now = SystemClock.uptimeMillis();
   1059             long nextTime = mLastLockTime + 100;
   1060             if (nextTime > now) {
   1061                 try {
   1062                     Thread.sleep(nextTime-now);
   1063                 } catch (InterruptedException e) {
   1064                 }
   1065                 now = SystemClock.uptimeMillis();
   1066             }
   1067             mLastLockTime = now;
   1068             mSurfaceLock.unlock();
   1069 
   1070             return null;
   1071         }
   1072 
   1073         /**
   1074          * Posts the new contents of the {@link Canvas} to the surface and
   1075          * releases the {@link Canvas}.
   1076          *
   1077          * @param canvas The canvas previously obtained from {@link #lockCanvas}.
   1078          */
   1079         @Override
   1080         public void unlockCanvasAndPost(Canvas canvas) {
   1081             mSurface.unlockCanvasAndPost(canvas);
   1082             mSurfaceLock.unlock();
   1083         }
   1084 
   1085         @Override
   1086         public Surface getSurface() {
   1087             return mSurface;
   1088         }
   1089 
   1090         @Override
   1091         public Rect getSurfaceFrame() {
   1092             return mSurfaceFrame;
   1093         }
   1094     };
   1095 
   1096     class SurfaceControlWithBackground extends SurfaceControl {
   1097         private SurfaceControl mBackgroundControl;
   1098         private boolean mOpaque = true;
   1099         public boolean mVisible = false;
   1100 
   1101         public SurfaceControlWithBackground(SurfaceSession s,
   1102                         String name, int w, int h, int format, int flags)
   1103                        throws Exception {
   1104             super(s, name, w, h, format, flags);
   1105             mBackgroundControl = new SurfaceControl(s, "Background for - " + name, w, h,
   1106                     PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
   1107             mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
   1108         }
   1109 
   1110         @Override
   1111         public void setAlpha(float alpha) {
   1112             super.setAlpha(alpha);
   1113             mBackgroundControl.setAlpha(alpha);
   1114         }
   1115 
   1116         @Override
   1117         public void setLayer(int zorder) {
   1118             super.setLayer(zorder);
   1119             // -3 is below all other child layers as SurfaceView never goes below -2
   1120             mBackgroundControl.setLayer(-3);
   1121         }
   1122 
   1123         @Override
   1124         public void setPosition(float x, float y) {
   1125             super.setPosition(x, y);
   1126             mBackgroundControl.setPosition(x, y);
   1127         }
   1128 
   1129         @Override
   1130         public void setSize(int w, int h) {
   1131             super.setSize(w, h);
   1132             mBackgroundControl.setSize(w, h);
   1133         }
   1134 
   1135         @Override
   1136         public void setWindowCrop(Rect crop) {
   1137             super.setWindowCrop(crop);
   1138             mBackgroundControl.setWindowCrop(crop);
   1139         }
   1140 
   1141         @Override
   1142         public void setFinalCrop(Rect crop) {
   1143             super.setFinalCrop(crop);
   1144             mBackgroundControl.setFinalCrop(crop);
   1145         }
   1146 
   1147         @Override
   1148         public void setLayerStack(int layerStack) {
   1149             super.setLayerStack(layerStack);
   1150             mBackgroundControl.setLayerStack(layerStack);
   1151         }
   1152 
   1153         @Override
   1154         public void setOpaque(boolean isOpaque) {
   1155             super.setOpaque(isOpaque);
   1156             mOpaque = isOpaque;
   1157             updateBackgroundVisibility();
   1158         }
   1159 
   1160         @Override
   1161         public void setSecure(boolean isSecure) {
   1162             super.setSecure(isSecure);
   1163         }
   1164 
   1165         @Override
   1166         public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
   1167             super.setMatrix(dsdx, dtdx, dsdy, dtdy);
   1168             mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
   1169         }
   1170 
   1171         @Override
   1172         public void hide() {
   1173             super.hide();
   1174             mVisible = false;
   1175             updateBackgroundVisibility();
   1176         }
   1177 
   1178         @Override
   1179         public void show() {
   1180             super.show();
   1181             mVisible = true;
   1182             updateBackgroundVisibility();
   1183         }
   1184 
   1185         @Override
   1186         public void destroy() {
   1187             super.destroy();
   1188             mBackgroundControl.destroy();
   1189          }
   1190 
   1191         @Override
   1192         public void release() {
   1193             super.release();
   1194             mBackgroundControl.release();
   1195         }
   1196 
   1197         @Override
   1198         public void setTransparentRegionHint(Region region) {
   1199             super.setTransparentRegionHint(region);
   1200             mBackgroundControl.setTransparentRegionHint(region);
   1201         }
   1202 
   1203         @Override
   1204         public void deferTransactionUntil(IBinder handle, long frame) {
   1205             super.deferTransactionUntil(handle, frame);
   1206             mBackgroundControl.deferTransactionUntil(handle, frame);
   1207         }
   1208 
   1209         @Override
   1210         public void deferTransactionUntil(Surface barrier, long frame) {
   1211             super.deferTransactionUntil(barrier, frame);
   1212             mBackgroundControl.deferTransactionUntil(barrier, frame);
   1213         }
   1214 
   1215         void updateBackgroundVisibility() {
   1216             if (mOpaque && mVisible) {
   1217                 mBackgroundControl.show();
   1218             } else {
   1219                 mBackgroundControl.hide();
   1220             }
   1221         }
   1222     }
   1223 }
   1224