SurfaceView(7)SurfaceView源码
代码:
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 android.util.DisplayMetrics; 20 import com.android.internal.view.BaseIWindow; 21 22 import android.content.Context; 23 import android.content.res.Configuration; 24 import android.content.res.Resources; 25 import android.content.res.CompatibilityInfo.Translator; 26 import android.graphics.Canvas; 27 import android.graphics.PixelFormat; 28 import android.graphics.PorterDuff; 29 import android.graphics.Rect; 30 import android.graphics.Region; 31 import android.os.Handler; 32 import android.os.Message; 33 import android.os.RemoteException; 34 import android.os.SystemClock; 35 import android.os.ParcelFileDescriptor; 36 import android.util.AttributeSet; 37 import android.util.Config; 38 import android.util.Log; 39 40 import java.lang.ref.WeakReference; 41 import java.util.ArrayList; 42 import java.util.concurrent.locks.ReentrantLock; 43 44 /** 45 * Provides a dedicated drawing surface embedded inside of a view hierarchy. 46 * You can control the format of this surface and, if you like, its size; the 47 * SurfaceView takes care of placing the surface at the correct location on the 48 * screen 49 * 50 * <p>The surface is Z ordered so that it is behind the window holding its 51 * SurfaceView; the SurfaceView punches a hole in its window to allow its 52 * surface to be displayed. The view hierarchy will take care of correctly 53 * compositing with the Surface any siblings of the SurfaceView that would 54 * normally appear on top of it. This can be used to place overlays such as 55 * buttons on top of the Surface, though note however that it can have an 56 * impact on performance since a full alpha-blended composite will be performed 57 * each time the Surface changes. 58 * 59 * <p>Access to the underlying surface is provided via the SurfaceHolder interface, 60 * which can be retrieved by calling {@link #getHolder}. 61 * 62 * <p>The Surface will be created for you while the SurfaceView's window is 63 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated} 64 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the 65 * Surface is created and destroyed as the window is shown and hidden. 66 * 67 * <p>One of the purposes of this class is to provide a surface in which a 68 * secondary thread can render in to the screen. If you are going to use it 69 * this way, you need to be aware of some threading semantics: 70 * 71 * <ul> 72 * <li> All SurfaceView and 73 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called 74 * from the thread running the SurfaceView's window (typically the main thread 75 * of the application). They thus need to correctly synchronize with any 76 * state that is also touched by the drawing thread. 77 * <li> You must ensure that the drawing thread only touches the underlying 78 * Surface while it is valid -- between 79 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()} 80 * and 81 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}. 82 * </ul> 83 */ 84 public class SurfaceView extends View { 85 static private final String TAG = "SurfaceView"; 86 static private final boolean DEBUG = false; 87 static private final boolean localLOGV = DEBUG ? true : Config.LOGV; 88 89 final ArrayList<SurfaceHolder.Callback> mCallbacks 90 = new ArrayList<SurfaceHolder.Callback>(); 91 92 final int[] mLocation = new int[2]; 93 94 final ReentrantLock mSurfaceLock = new ReentrantLock(); 95 final Surface mSurface = new Surface(); 96 boolean mDrawingStopped = true; 97 98 final WindowManager.LayoutParams mLayout 99 = new WindowManager.LayoutParams(); 100 IWindowSession mSession; 101 MyWindow mWindow; 102 final Rect mVisibleInsets = new Rect(); 103 final Rect mWinFrame = new Rect(); 104 final Rect mContentInsets = new Rect(); 105 final Configuration mConfiguration = new Configuration(); 106 107 static final int KEEP_SCREEN_ON_MSG = 1; 108 static final int GET_NEW_SURFACE_MSG = 2; 109 static final int UPDATE_WINDOW_MSG = 3; 110 111 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; 112 113 boolean mIsCreating = false; 114 115 final Handler mHandler = new Handler() { 116 @Override 117 public void handleMessage(Message msg) { 118 switch (msg.what) { 119 case KEEP_SCREEN_ON_MSG: { 120 setKeepScreenOn(msg.arg1 != 0); 121 } break; 122 case GET_NEW_SURFACE_MSG: { 123 handleGetNewSurface(); 124 } break; 125 case UPDATE_WINDOW_MSG: { 126 updateWindow(false); 127 } break; 128 } 129 } 130 }; 131 132 final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener 133 = new ViewTreeObserver.OnScrollChangedListener() { 134 public void onScrollChanged() { 135 updateWindow(false); 136 } 137 }; 138 139 boolean mRequestedVisible = false; 140 boolean mWindowVisibility = false; 141 boolean mViewVisibility = false; 142 int mRequestedWidth = -1; 143 int mRequestedHeight = -1; 144 int mRequestedFormat = PixelFormat.OPAQUE; 145 int mRequestedType = -1; 146 147 boolean mHaveFrame = false; 148 boolean mDestroyReportNeeded = false; 149 boolean mNewSurfaceNeeded = false; 150 long mLastLockTime = 0; 151 152 boolean mVisible = false; 153 int mLeft = -1; 154 int mTop = -1; 155 int mWidth = -1; 156 int mHeight = -1; 157 int mFormat = -1; 158 int mType = -1; 159 final Rect mSurfaceFrame = new Rect(); 160 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1; 161 boolean mUpdateWindowNeeded; 162 boolean mReportDrawNeeded; 163 private Translator mTranslator; 164 165 public SurfaceView(Context context) { 166 super(context); 167 setWillNotDraw(true); 168 } 169 170 public SurfaceView(Context context, AttributeSet attrs) { 171 super(context, attrs); 172 setWillNotDraw(true); 173 } 174 175 public SurfaceView(Context context, AttributeSet attrs, int defStyle) { 176 super(context, attrs, defStyle); 177 setWillNotDraw(true); 178 } 179 180 /** 181 * Return the SurfaceHolder providing access and control over this 182 * SurfaceView's underlying surface. 183 * 184 * @return SurfaceHolder The holder of the surface. 185 */ 186 public SurfaceHolder getHolder() { 187 return mSurfaceHolder; 188 } 189 190 @Override 191 protected void onAttachedToWindow() { 192 super.onAttachedToWindow(); 193 mParent.requestTransparentRegion(this); 194 mSession = getWindowSession(); 195 mLayout.token = getWindowToken(); 196 mLayout.setTitle("SurfaceView"); 197 mViewVisibility = getVisibility() == VISIBLE; 198 getViewTreeObserver().addOnScrollChangedListener(mScrollChangedListener); 199 } 200 201 @Override 202 protected void onWindowVisibilityChanged(int visibility) { 203 super.onWindowVisibilityChanged(visibility); 204 mWindowVisibility = visibility == VISIBLE; 205 mRequestedVisible = mWindowVisibility && mViewVisibility; 206 updateWindow(false); 207 } 208 209 @Override 210 public void setVisibility(int visibility) { 211 super.setVisibility(visibility); 212 mViewVisibility = visibility == VISIBLE; 213 mRequestedVisible = mWindowVisibility && mViewVisibility; 214 updateWindow(false); 215 } 216 217 /** 218 * This method is not intended for general use. It was created 219 * temporarily to improve performance of 3D layers in Launcher 220 * and should be removed and fixed properly. 221 * 222 * Do not call this method. Ever. 223 * 224 * @hide 225 */ 226 protected void showSurface() { 227 if (mSession != null) { 228 updateWindow(true); 229 } 230 } 231 232 /** 233 * This method is not intended for general use. It was created 234 * temporarily to improve performance of 3D layers in Launcher 235 * and should be removed and fixed properly. 236 * 237 * Do not call this method. Ever. 238 * 239 * @hide 240 */ 241 protected void hideSurface() { 242 if (mSession != null && mWindow != null) { 243 mSurfaceLock.lock(); 244 try { 245 DisplayMetrics metrics = getResources().getDisplayMetrics(); 246 mLayout.x = metrics.widthPixels * 3; 247 mSession.relayout(mWindow, mLayout, mWidth, mHeight, VISIBLE, false, 248 mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface); 249 } catch (RemoteException e) { 250 // Ignore 251 } finally { 252 mSurfaceLock.unlock(); 253 } 254 } 255 } 256 257 @Override 258 protected void onDetachedFromWindow() { 259 getViewTreeObserver().removeOnScrollChangedListener(mScrollChangedListener); 260 mRequestedVisible = false; 261 updateWindow(false); 262 mHaveFrame = false; 263 if (mWindow != null) { 264 try { 265 mSession.remove(mWindow); 266 } catch (RemoteException ex) { 267 } 268 mWindow = null; 269 } 270 mSession = null; 271 mLayout.token = null; 272 273 super.onDetachedFromWindow(); 274 } 275 276 @Override 277 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 278 int width = getDefaultSize(mRequestedWidth, widthMeasureSpec); 279 int height = getDefaultSize(mRequestedHeight, heightMeasureSpec); 280 setMeasuredDimension(width, height); 281 } 282 283 @Override 284 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 285 super.onSizeChanged(w, h, oldw, oldh); 286 updateWindow(false); 287 } 288 289 @Override 290 public boolean gatherTransparentRegion(Region region) { 291 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { 292 return super.gatherTransparentRegion(region); 293 } 294 295 boolean opaque = true; 296 if ((mPrivateFlags & SKIP_DRAW) == 0) { 297 // this view draws, remove it from the transparent region 298 opaque = super.gatherTransparentRegion(region); 299 } else if (region != null) { 300 int w = getWidth(); 301 int h = getHeight(); 302 if (w>0 && h>0) { 303 getLocationInWindow(mLocation); 304 // otherwise, punch a hole in the whole hierarchy 305 int l = mLocation[0]; 306 int t = mLocation[1]; 307 region.op(l, t, l+w, t+h, Region.Op.UNION); 308 } 309 } 310 if (PixelFormat.formatHasAlpha(mRequestedFormat)) { 311 opaque = false; 312 } 313 return opaque; 314 } 315 316 @Override 317 public void draw(Canvas canvas) { 318 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { 319 // draw() is not called when SKIP_DRAW is set 320 if ((mPrivateFlags & SKIP_DRAW) == 0) { 321 // punch a whole in the view-hierarchy below us 322 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 323 } 324 } 325 super.draw(canvas); 326 } 327 328 @Override 329 protected void dispatchDraw(Canvas canvas) { 330 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { 331 // if SKIP_DRAW is cleared, draw() has already punched a hole 332 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { 333 // punch a whole in the view-hierarchy below us 334 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 335 } 336 } 337 // reposition ourselves where the surface is 338 mHaveFrame = true; 339 updateWindow(false); 340 super.dispatchDraw(canvas); 341 } 342 343 /** 344 * Control whether the surface view's surface is placed on top of another 345 * regular surface view in the window (but still behind the window itself). 346 * This is typically used to place overlays on top of an underlying media 347 * surface view. 348 * 349 * <p>Note that this must be set before the surface view's containing 350 * window is attached to the window manager. 351 * 352 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}. 353 */ 354 public void setZOrderMediaOverlay(boolean isMediaOverlay) { 355 mWindowType = isMediaOverlay 356 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY 357 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; 358 } 359 360 /** 361 * Control whether the surface view's surface is placed on top of its 362 * window. Normally it is placed behind the window, to allow it to 363 * (for the most part) appear to composite with the views in the 364 * hierarchy. By setting this, you cause it to be placed above the 365 * window. This means that none of the contents of the window this 366 * SurfaceView is in will be visible on top of its surface. 367 * 368 * <p>Note that this must be set before the surface view's containing 369 * window is attached to the window manager. 370 * 371 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}. 372 */ 373 public void setZOrderOnTop(boolean onTop) { 374 if (onTop) { 375 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; 376 // ensures the surface is placed below the IME 377 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 378 } else { 379 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; 380 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 381 } 382 } 383 384 /** 385 * Hack to allow special layering of windows. The type is one of the 386 * types in WindowManager.LayoutParams. This is a hack so: 387 * @hide 388 */ 389 public void setWindowType(int type) { 390 mWindowType = type; 391 } 392 393 private void updateWindow(boolean force) { 394 if (!mHaveFrame) { 395 return; 396 } 397 ViewRoot viewRoot = (ViewRoot) getRootView().getParent(); 398 if (viewRoot != null) { 399 mTranslator = viewRoot.mTranslator; 400 } 401 402 Resources res = getContext().getResources(); 403 if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) { 404 mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator); 405 } 406 407 int myWidth = mRequestedWidth; 408 if (myWidth <= 0) myWidth = getWidth(); 409 int myHeight = mRequestedHeight; 410 if (myHeight <= 0) myHeight = getHeight(); 411 412 getLocationInWindow(mLocation); 413 final boolean creating = mWindow == null; 414 final boolean formatChanged = mFormat != mRequestedFormat; 415 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; 416 final boolean visibleChanged = mVisible != mRequestedVisible 417 || mNewSurfaceNeeded; 418 final boolean typeChanged = mType != mRequestedType; 419 if (force || creating || formatChanged || sizeChanged || visibleChanged 420 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1] 421 || mUpdateWindowNeeded || mReportDrawNeeded) { 422 423 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating 424 + " format=" + formatChanged + " size=" + sizeChanged 425 + " visible=" + visibleChanged 426 + " left=" + (mLeft != mLocation[0]) 427 + " top=" + (mTop != mLocation[1])); 428 429 try { 430 final boolean visible = mVisible = mRequestedVisible; 431 mLeft = mLocation[0]; 432 mTop = mLocation[1]; 433 mWidth = myWidth; 434 mHeight = myHeight; 435 mFormat = mRequestedFormat; 436 mType = mRequestedType; 437 438 // Scaling/Translate window's layout here because mLayout is not used elsewhere. 439 440 // Places the window relative 441 mLayout.x = mLeft; 442 mLayout.y = mTop; 443 mLayout.width = getWidth(); 444 mLayout.height = getHeight(); 445 if (mTranslator != null) { 446 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout); 447 } 448 449 mLayout.format = mRequestedFormat; 450 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 451 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 452 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 453 | WindowManager.LayoutParams.FLAG_SCALED 454 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 455 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 456 ; 457 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) { 458 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; 459 } 460 461 mLayout.memoryType = mRequestedType; 462 463 if (mWindow == null) { 464 mWindow = new MyWindow(this); 465 mLayout.type = mWindowType; 466 mLayout.gravity = Gravity.LEFT|Gravity.TOP; 467 mSession.add(mWindow, mLayout, 468 mVisible ? VISIBLE : GONE, mContentInsets); 469 } 470 471 if (visibleChanged && (!visible || mNewSurfaceNeeded)) { 472 reportSurfaceDestroyed(); 473 } 474 475 mNewSurfaceNeeded = false; 476 477 boolean realSizeChanged; 478 boolean reportDrawNeeded; 479 480 mSurfaceLock.lock(); 481 try { 482 mUpdateWindowNeeded = false; 483 reportDrawNeeded = mReportDrawNeeded; 484 mReportDrawNeeded = false; 485 mDrawingStopped = !visible; 486 487 final int relayoutResult = mSession.relayout( 488 mWindow, mLayout, mWidth, mHeight, 489 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets, 490 mVisibleInsets, mConfiguration, mSurface); 491 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { 492 mReportDrawNeeded = true; 493 } 494 495 if (localLOGV) Log.i(TAG, "New surface: " + mSurface 496 + ", vis=" + visible + ", frame=" + mWinFrame); 497 498 mSurfaceFrame.left = 0; 499 mSurfaceFrame.top = 0; 500 if (mTranslator == null) { 501 mSurfaceFrame.right = mWinFrame.width(); 502 mSurfaceFrame.bottom = mWinFrame.height(); 503 } else { 504 float appInvertedScale = mTranslator.applicationInvertedScale; 505 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f); 506 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f); 507 } 508 509 final int surfaceWidth = mSurfaceFrame.right; 510 final int surfaceHeight = mSurfaceFrame.bottom; 511 realSizeChanged = mLastSurfaceWidth != surfaceWidth 512 || mLastSurfaceHeight != surfaceHeight; 513 mLastSurfaceWidth = surfaceWidth; 514 mLastSurfaceHeight = surfaceHeight; 515 } finally { 516 mSurfaceLock.unlock(); 517 } 518 519 try { 520 if (visible) { 521 mDestroyReportNeeded = true; 522 523 SurfaceHolder.Callback callbacks[]; 524 synchronized (mCallbacks) { 525 callbacks = new SurfaceHolder.Callback[mCallbacks.size()]; 526 mCallbacks.toArray(callbacks); 527 } 528 529 if (visibleChanged) { 530 mIsCreating = true; 531 for (SurfaceHolder.Callback c : callbacks) { 532 c.surfaceCreated(mSurfaceHolder); 533 } 534 } 535 if (creating || formatChanged || sizeChanged 536 || visibleChanged || realSizeChanged) { 537 for (SurfaceHolder.Callback c : callbacks) { 538 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight); 539 } 540 } 541 } else { 542 mSurface.release(); 543 } 544 } finally { 545 mIsCreating = false; 546 if (creating || reportDrawNeeded) { 547 mSession.finishDrawing(mWindow); 548 } 549 } 550 } catch (RemoteException ex) { 551 } 552 if (localLOGV) Log.v( 553 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + 554 " w=" + mLayout.width + " h=" + mLayout.height + 555 ", frame=" + mSurfaceFrame); 556 } 557 } 558 559 private void reportSurfaceDestroyed() { 560 if (mDestroyReportNeeded) { 561 mDestroyReportNeeded = false; 562 SurfaceHolder.Callback callbacks[]; 563 synchronized (mCallbacks) { 564 callbacks = new SurfaceHolder.Callback[mCallbacks.size()]; 565 mCallbacks.toArray(callbacks); 566 } 567 for (SurfaceHolder.Callback c : callbacks) { 568 c.surfaceDestroyed(mSurfaceHolder); 569 } 570 } 571 super.onDetachedFromWindow(); 572 } 573 574 void handleGetNewSurface() { 575 mNewSurfaceNeeded = true; 576 updateWindow(false); 577 } 578 579 /** 580 * Check to see if the surface has fixed size dimensions or if the surface's 581 * dimensions are dimensions are dependent on its current layout. 582 * 583 * @return true if the surface has dimensions that are fixed in size 584 * @hide 585 */ 586 public boolean isFixedSize() { 587 return (mRequestedWidth != -1 || mRequestedHeight != -1); 588 } 589 590 private static class MyWindow extends BaseIWindow { 591 private final WeakReference<SurfaceView> mSurfaceView; 592 593 public MyWindow(SurfaceView surfaceView) { 594 mSurfaceView = new WeakReference<SurfaceView>(surfaceView); 595 } 596 597 public void resized(int w, int h, Rect coveredInsets, 598 Rect visibleInsets, boolean reportDraw, Configuration newConfig) { 599 SurfaceView surfaceView = mSurfaceView.get(); 600 if (surfaceView != null) { 601 if (localLOGV) Log.v( 602 "SurfaceView", surfaceView + " got resized: w=" + 603 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight); 604 surfaceView.mSurfaceLock.lock(); 605 try { 606 if (reportDraw) { 607 surfaceView.mUpdateWindowNeeded = true; 608 surfaceView.mReportDrawNeeded = true; 609 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG); 610 } else if (surfaceView.mWinFrame.width() != w 611 || surfaceView.mWinFrame.height() != h) { 612 surfaceView.mUpdateWindowNeeded = true; 613 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG); 614 } 615 } finally { 616 surfaceView.mSurfaceLock.unlock(); 617 } 618 } 619 } 620 621 public void dispatchKey(KeyEvent event) { 622 SurfaceView surfaceView = mSurfaceView.get(); 623 if (surfaceView != null) { 624 //Log.w("SurfaceView", "Unexpected key event in surface: " + event); 625 if (surfaceView.mSession != null && surfaceView.mSurface != null) { 626 try { 627 surfaceView.mSession.finishKey(surfaceView.mWindow); 628 } catch (RemoteException ex) { 629 } 630 } 631 } 632 } 633 634 public void dispatchPointer(MotionEvent event, long eventTime, 635 boolean callWhenDone) { 636 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event); 637 //if (mSession != null && mSurface != null) { 638 // try { 639 // //mSession.finishKey(mWindow); 640 // } catch (RemoteException ex) { 641 // } 642 //} 643 } 644 645 public void dispatchTrackball(MotionEvent event, long eventTime, 646 boolean callWhenDone) { 647 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event); 648 //if (mSession != null && mSurface != null) { 649 // try { 650 // //mSession.finishKey(mWindow); 651 // } catch (RemoteException ex) { 652 // } 653 //} 654 } 655 656 public void dispatchAppVisibility(boolean visible) { 657 // The point of SurfaceView is to let the app control the surface. 658 } 659 660 public void dispatchGetNewSurface() { 661 SurfaceView surfaceView = mSurfaceView.get(); 662 if (surfaceView != null) { 663 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG); 664 surfaceView.mHandler.sendMessage(msg); 665 } 666 } 667 668 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) { 669 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled); 670 } 671 672 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { 673 } 674 675 int mCurWidth = -1; 676 int mCurHeight = -1; 677 } 678 679 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() { 680 681 private static final String LOG_TAG = "SurfaceHolder"; 682 private int mSaveCount; 683 684 public boolean isCreating() { 685 return mIsCreating; 686 } 687 688 public void addCallback(Callback callback) { 689 synchronized (mCallbacks) { 690 // This is a linear search, but in practice we'll 691 // have only a couple callbacks, so it doesn't matter. 692 if (mCallbacks.contains(callback) == false) { 693 mCallbacks.add(callback); 694 } 695 } 696 } 697 698 public void removeCallback(Callback callback) { 699 synchronized (mCallbacks) { 700 mCallbacks.remove(callback); 701 } 702 } 703 704 public void setFixedSize(int width, int height) { 705 if (mRequestedWidth != width || mRequestedHeight != height) { 706 mRequestedWidth = width; 707 mRequestedHeight = height; 708 requestLayout(); 709 } 710 } 711 712 public void setSizeFromLayout() { 713 if (mRequestedWidth != -1 || mRequestedHeight != -1) { 714 mRequestedWidth = mRequestedHeight = -1; 715 requestLayout(); 716 } 717 } 718 719 public void setFormat(int format) { 720 mRequestedFormat = format; 721 if (mWindow != null) { 722 updateWindow(false); 723 } 724 } 725 726 public void setType(int type) { 727 switch (type) { 728 case SURFACE_TYPE_HARDWARE: 729 case SURFACE_TYPE_GPU: 730 // these are deprecated, treat as "NORMAL" 731 type = SURFACE_TYPE_NORMAL; 732 break; 733 } 734 switch (type) { 735 case SURFACE_TYPE_NORMAL: 736 case SURFACE_TYPE_PUSH_BUFFERS: 737 mRequestedType = type; 738 if (mWindow != null) { 739 updateWindow(false); 740 } 741 break; 742 } 743 } 744 745 public void setKeepScreenOn(boolean screenOn) { 746 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG); 747 msg.arg1 = screenOn ? 1 : 0; 748 mHandler.sendMessage(msg); 749 } 750 751 public Canvas lockCanvas() { 752 return internalLockCanvas(null); 753 } 754 755 public Canvas lockCanvas(Rect dirty) { 756 return internalLockCanvas(dirty); 757 } 758 759 private final Canvas internalLockCanvas(Rect dirty) { 760 if (mType == SURFACE_TYPE_PUSH_BUFFERS) { 761 throw new BadSurfaceTypeException( 762 "Surface type is SURFACE_TYPE_PUSH_BUFFERS"); 763 } 764 mSurfaceLock.lock(); 765 766 if (localLOGV) Log.i(TAG, "Locking canvas... stopped=" 767 + mDrawingStopped + ", win=" + mWindow); 768 769 Canvas c = null; 770 if (!mDrawingStopped && mWindow != null) { 771 Rect frame = dirty != null ? dirty : mSurfaceFrame; 772 try { 773 c = mSurface.lockCanvas(frame); 774 } catch (Exception e) { 775 Log.e(LOG_TAG, "Exception locking surface", e); 776 } 777 } 778 779 if (localLOGV) Log.i(TAG, "Returned canvas: " + c); 780 if (c != null) { 781 mLastLockTime = SystemClock.uptimeMillis(); 782 return c; 783 } 784 785 // If the Surface is not ready to be drawn, then return null, 786 // but throttle calls to this function so it isn't called more 787 // than every 100ms. 788 long now = SystemClock.uptimeMillis(); 789 long nextTime = mLastLockTime + 100; 790 if (nextTime > now) { 791 try { 792 Thread.sleep(nextTime-now); 793 } catch (InterruptedException e) { 794 } 795 now = SystemClock.uptimeMillis(); 796 } 797 mLastLockTime = now; 798 mSurfaceLock.unlock(); 799 800 return null; 801 } 802 803 public void unlockCanvasAndPost(Canvas canvas) { 804 mSurface.unlockCanvasAndPost(canvas); 805 mSurfaceLock.unlock(); 806 } 807 808 public Surface getSurface() { 809 return mSurface; 810 } 811 812 public Rect getSurfaceFrame() { 813 return mSurfaceFrame; 814 } 815 }; 816 }

浙公网安备 33010602011771号