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