下面列出了怎么用android.view.SurfaceControl的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,
long presentationDeadlineNanos, int state) {
synchronized (getSyncRoot()) {
IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
mDevice = new OverlayDisplayDevice(displayToken, mName, mModes, mActiveMode,
DEFAULT_MODE_INDEX, refreshRate, presentationDeadlineNanos,
mSecure, state, surfaceTexture, mNumber) {
@Override
public void onModeChangedLocked(int index) {
onActiveModeChangedLocked(index);
}
};
sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
}
}
private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
float alpha) {
final DimState d = getDimState(container);
if (d == null) {
return;
}
if (container != null) {
// The dim method is called from WindowState.prepareSurfaces(), which is always called
// in the correct Z from lowest Z to highest. This ensures that the dim layer is always
// relative to the highest Z layer with a dim.
t.setRelativeLayer(d.mDimLayer, container.getSurfaceControl(), relativeLayer);
} else {
t.setLayer(d.mDimLayer, Integer.MAX_VALUE);
}
t.setAlpha(d.mDimLayer, alpha);
d.mDimming = true;
}
private void setSnapshotTransform(SurfaceControl.Transaction t, Matrix matrix, float alpha) {
if (mSurfaceControl != null) {
matrix.getValues(mTmpFloats);
float x = mTmpFloats[Matrix.MTRANS_X];
float y = mTmpFloats[Matrix.MTRANS_Y];
if (mForceDefaultOrientation) {
mDisplayContent.getBounds(mCurrentDisplayRect);
x -= mCurrentDisplayRect.left;
y -= mCurrentDisplayRect.top;
}
t.setPosition(mSurfaceControl, x, y);
t.setMatrix(mSurfaceControl,
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
t.setAlpha(mSurfaceControl, alpha);
if (DEBUG_TRANSFORMS) {
float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
float[] dstPnts = new float[4];
matrix.mapPoints(dstPnts, srcPnts);
Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
+ ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
+ ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
}
}
}
@VisibleForTesting
void performTraversalInternal(SurfaceControl.Transaction t) {
synchronized (mSyncRoot) {
if (!mPendingTraversal) {
return;
}
mPendingTraversal = false;
performTraversalLocked(t);
}
// List is self-synchronized copy-on-write.
for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
listener.onDisplayTransaction();
}
}
/**
* Returns true if animating.
*/
public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
if (mSurfaceControl == null) {
// Can't do animation.
return false;
}
if (!mStarted) {
startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
true, exitAnim, enterAnim);
}
if (!mStarted) {
return false;
}
if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true");
mFinishAnimReady = true;
return true;
}
private void destroySurface() {
if (mSurfaceControl != null) {
mSurfaceLayout.dispose();
mSurfaceLayout = null;
SurfaceControl.openTransaction();
try {
mSurfaceControl.destroy();
mSurface.release();
} finally {
SurfaceControl.closeTransaction();
}
mSurfaceControl = null;
mSurfaceVisible = false;
mSurfaceAlpha = 0f;
}
}
public EmulatorDisplayOverlay(Context context, DisplayContent dc,
int zOrder) {
final Display display = dc.getDisplay();
mScreenSize = new Point();
display.getSize(mScreenSize);
SurfaceControl ctrl = null;
try {
ctrl = dc.makeOverlay()
.setName("EmulatorDisplayOverlay")
.setSize(mScreenSize.x, mScreenSize.y)
.setFormat(PixelFormat.TRANSLUCENT)
.build();
ctrl.setLayer(zOrder);
ctrl.setPosition(0, 0);
ctrl.show();
mSurface.copyFrom(ctrl);
} catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
mDrawNeeded = true;
mOverlay = context.getDrawable(
com.android.internal.R.drawable.emulator_circular_window_overlay);
}
void setPosition(SurfaceControl.Transaction t, float left, float top,
boolean recoveringMemory) {
final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;
if (surfaceMoved) {
mSurfaceX = left;
mSurfaceY = top;
try {
if (SHOW_TRANSACTIONS) logSurface(
"POS (setPositionInTransaction) @ (" + left + "," + top + ")", null);
if (t == null) {
mSurfaceControl.setPosition(left, top);
} else {
t.setPosition(mSurfaceControl, left, top);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + this
+ " pos=(" + left + "," + top + ")", e);
if (!recoveringMemory) {
mAnimator.reclaimSomeSurfaceMemory("position", true);
}
}
}
}
@Override
public Bitmap takeScreenshot(Rect crop, int rotation) {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
int width = crop.width();
int height = crop.height();
return SurfaceControl.screenshot(crop, width, height, rotation);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
* Call after invoking {@link WindowContainer#prepareSurfaces} on children as
* described in {@link #resetDimStates}.
*
* @param t A transaction in which to update the dims.
* @param bounds The bounds at which to dim.
* @return true if any Dims were updated.
*/
boolean updateDims(SurfaceControl.Transaction t, Rect bounds) {
if (mDimState == null) {
return false;
}
if (!mDimState.mDimming) {
if (!mDimState.mAnimateExit) {
t.destroy(mDimState.mDimLayer);
} else {
startDimExit(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
}
mDimState = null;
return false;
} else {
// TODO: Once we use geometry from hierarchy this falls away.
t.setSize(mDimState.mDimLayer, bounds.width(), bounds.height());
t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top);
if (!mDimState.isVisible) {
mDimState.isVisible = true;
t.show(mDimState.mDimLayer);
startDimEnter(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
}
return true;
}
}
void onAnimationCancelled(SurfaceControl leash) {
synchronized (mLock) {
if (mPendingAnimations.containsKey(leash)) {
mPendingAnimations.remove(leash);
return;
}
final RunningAnimation anim = mRunningAnimations.get(leash);
if (anim != null) {
mRunningAnimations.remove(leash);
synchronized (mCancelLock) {
anim.mCancelled = true;
}
SurfaceAnimationThread.getHandler().post(() -> {
anim.mAnim.cancel();
applyTransaction();
});
}
}
}
@Override
public WindowAnimationFrameStats getWindowAnimationFrameStats() {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
WindowAnimationFrameStats stats = new WindowAnimationFrameStats();
SurfaceControl.getAnimationFrameStats(stats);
return stats;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
* Starts an animation.
*
* @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the
* component responsible for running the animation. It runs the animation with
* {@link AnimationAdapter#startAnimation} once the hierarchy with
* the Leash has been set up.
* @param hidden Whether the container holding the child surfaces is currently visible or not.
* This is important as it will start with the leash hidden or visible before
* handing it to the component that is responsible to run the animation.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mAnimation = anim;
final SurfaceControl surface = mAnimatable.getSurfaceControl();
if (surface == null) {
Slog.w(TAG, "Unable to start animation, surface is null or no children.");
cancelAnimation();
return;
}
mLeash = createAnimationLeash(surface, t,
mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden);
mAnimatable.onAnimationLeashCreated(t, mLeash);
if (mAnimationStartDelayed) {
if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
return;
}
mAnimation.startAnimation(mLeash, t, mInnerAnimationFinishedCallback);
}
void transferAnimation(SurfaceAnimator from) {
if (from.mLeash == null) {
return;
}
final SurfaceControl surface = mAnimatable.getSurfaceControl();
final SurfaceControl parent = mAnimatable.getAnimationLeashParent();
if (surface == null || parent == null) {
Slog.w(TAG, "Unable to transfer animation, surface or parent is null");
cancelAnimation();
return;
}
endDelayingAnimationStart();
final Transaction t = mAnimatable.getPendingTransaction();
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mLeash = from.mLeash;
mAnimation = from.mAnimation;
// Cancel source animation, but don't let animation runner cancel the animation.
from.cancelAnimation(t, false /* restarting */, false /* forwardCancel */);
t.reparent(surface, mLeash.getHandle());
t.reparent(mLeash, parent.getHandle());
mAnimatable.onAnimationLeashCreated(t, mLeash);
mService.mAnimationTransferMap.put(mAnimation, this);
}
public void applySurfaceChanges(SurfaceControl.Transaction t) {
if (mSurfaceFrame.equals(mLayoutFrame)) {
// Nothing changed.
return;
}
mSurfaceFrame.set(mLayoutFrame);
if (!mSurfaceFrame.isEmpty()) {
if (mSurface == null) {
createSurface();
}
t.setPosition(mSurface, mSurfaceFrame.left, mSurfaceFrame.top);
t.setSize(mSurface, mSurfaceFrame.width(), mSurfaceFrame.height());
t.show(mSurface);
} else if (mSurface != null) {
t.hide(mSurface);
}
}
@Override
public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
final TmpValues tmp = mThreadLocalTmps.get();
tmp.transformation.clear();
mAnimation.getTransformation(currentPlayTime, tmp.transformation);
tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
t.setAlpha(leash, tmp.transformation.getAlpha());
if (mStackClipMode == STACK_CLIP_NONE) {
t.setWindowCrop(leash, tmp.transformation.getClipRect());
} else if (mStackClipMode == STACK_CLIP_AFTER_ANIM) {
mTmpRect.set(mStackBounds);
// Offset stack bounds to stack position so the final crop is in screen space.
mTmpRect.offsetTo(mPosition.x, mPosition.y);
t.setFinalCrop(leash, mTmpRect);
t.setWindowCrop(leash, tmp.transformation.getClipRect());
} else {
mTmpRect.set(mStackBounds);
mTmpRect.intersect(tmp.transformation.getClipRect());
t.setWindowCrop(leash, mTmpRect);
}
}
BlackSurface(SurfaceControl.Transaction transaction, int layer,
int l, int t, int r, int b, DisplayContent dc) throws OutOfResourcesException {
left = l;
top = t;
this.layer = layer;
int w = r-l;
int h = b-t;
surface = dc.makeOverlay()
.setName("BlackSurface")
.setSize(w, h)
.setColorLayer(true)
.setParent(null) // TODO: Work-around for b/69259549
.build();
transaction.setAlpha(surface, 1);
transaction.setLayer(surface, layer);
transaction.show(surface);
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
" BLACK " + surface + ": CREATE layer=" + layer);
}
@Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
// The leash is parented to the animation layer. We need to preserve the z-order by using
// the prefix order index, but we boost if necessary.
int layer = 0;
if (!inPinnedWindowingMode()) {
layer = getPrefixOrderIndex();
} else {
// Pinned stacks have animations take place within themselves rather than an animation
// layer so we need to preserve the order relative to the stack (e.g. the order of our
// task/parent).
layer = getParent().getPrefixOrderIndex();
}
if (mNeedsZBoost) {
layer += Z_BOOST_BASE;
}
leash.setLayer(layer);
final DisplayContent dc = getDisplayContent();
dc.assignStackOrdering();
if (mAnimatingAppWindowTokenRegistry != null) {
mAnimatingAppWindowTokenRegistry.notifyStarting(this);
}
}
public boolean setRotation(SurfaceControl.Transaction t, int rotation,
long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) {
setRotation(t, rotation);
if (TWO_PHASE_ANIMATION) {
return startAnimation(t, maxAnimationDuration, animationScale,
finalWidth, finalHeight, false, 0, 0);
}
// Don't start animation yet.
return false;
}
DragState(WindowManagerService service, DragDropController controller, IBinder token,
SurfaceControl surface, int flags, IBinder localWin) {
mService = service;
mDragDropController = controller;
mToken = token;
mSurfaceControl = surface;
mFlags = flags;
mLocalWin = localWin;
mNotifiedWindows = new ArrayList<WindowState>();
}
private DisplayModeRecord findDisplayModeRecord(SurfaceControl.PhysicalDisplayInfo info) {
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
if (record.hasMatchingMode(info)) {
return record;
}
}
return null;
}
DimState(SurfaceControl dimLayer) {
mDimLayer = dimLayer;
mDimming = true;
mSurfaceAnimator = new SurfaceAnimator(new DimAnimatable(dimLayer), () -> {
if (!mDimming) {
mDimLayer.destroy();
}
}, mHost.mService);
}
public boolean requestColorModeLocked(int colorMode) {
if (mActiveColorMode == colorMode) {
return false;
}
if (!mSupportedColorModes.contains(colorMode)) {
Slog.w(TAG, "Unable to find color mode " + colorMode
+ ", ignoring request.");
return false;
}
SurfaceControl.setActiveColorMode(getDisplayTokenLocked(), colorMode);
mActiveColorMode = colorMode;
mActiveColorModeInvalid = false;
return true;
}
private int findDisplayInfoIndexLocked(int modeId) {
DisplayModeRecord record = mSupportedModes.get(modeId);
if (record != null) {
for (int i = 0; i < mDisplayInfos.length; i++) {
SurfaceControl.PhysicalDisplayInfo info = mDisplayInfos[i];
if (record.hasMatchingMode(info)){
return i;
}
}
}
return -1;
}
private void applySurfaceChangesTransaction(boolean recoveringMemory, int defaultDw,
int defaultDh) {
mHoldScreenWindow = null;
mObscuringWindow = null;
// TODO(multi-display): Support these features on secondary screens.
if (mService.mWatermark != null) {
mService.mWatermark.positionSurface(defaultDw, defaultDh);
}
if (mService.mStrictModeFlash != null) {
mService.mStrictModeFlash.positionSurface(defaultDw, defaultDh);
}
if (mService.mCircularDisplayMask != null) {
mService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
mService.getDefaultDisplayRotation());
}
if (mService.mEmulatorDisplayOverlay != null) {
mService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
mService.getDefaultDisplayRotation());
}
boolean focusDisplayed = false;
final int count = mChildren.size();
for (int j = 0; j < count; ++j) {
final DisplayContent dc = mChildren.get(j);
focusDisplayed |= dc.applySurfaceChangesTransaction(recoveringMemory);
}
if (focusDisplayed) {
mService.mH.sendEmptyMessage(REPORT_LOSING_FOCUS);
}
// Give the display manager a chance to adjust properties like display rotation if it needs
// to.
mService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
}
public void destroyLocked() {
if (mSurface != null) {
mSurface.release();
mSurface = null;
}
SurfaceControl.destroyDisplay(getDisplayTokenLocked());
}
public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
int displayId, SurfaceControl surfaceControl) {
mDisplayManagerInternal = displayManagerInternal;
mDisplayId = displayId;
mSurfaceControl = surfaceControl;
mDisplayManagerInternal.registerDisplayTransactionListener(this);
}
public void destroyLocked(boolean binderAlive) {
if (mSurface != null) {
mSurface.release();
mSurface = null;
}
SurfaceControl.destroyDisplay(getDisplayTokenLocked());
if (binderAlive) {
mCallback.dispatchDisplayStopped();
}
}
@Override
public void performTraversalLocked(SurfaceControl.Transaction t) {
if ((mPendingChanges & PENDING_RESIZE) != 0) {
t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
}
if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
setSurfaceLocked(t, mSurface);
}
mPendingChanges = 0;
}
@Override
public void onAnimationCancelled(SurfaceControl animationLeash) {
mPendingAnimations.remove(this);
if (mPendingAnimations.isEmpty()) {
mHandler.removeCallbacks(mTimeoutRunnable);
releaseFinishedCallback();
invokeAnimationCancelled();
sendRunningRemoteAnimation(false);
}
}