* @param attachInfo AttachInfo tied to the specified view.
* @param callbacks Callbacks invoked when drawing happens.
*/
- void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
+ void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks,
+ FrameDrawingCallback frameDrawingCallback) {
final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
choreographer.mFrameInfo.markDrawStart();
}
final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
+ if (frameDrawingCallback != null) {
+ nSetFrameCallback(mNativeProxy, frameDrawingCallback);
+ }
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
setEnabled(false);
import android.util.TimeUtils;
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
+import android.view.ThreadedRenderer.FrameDrawingCallback;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
static boolean sFirstDrawComplete = false;
+ private FrameDrawingCallback mNextRtFrameCallback;
+
/**
* Callback for notifying about global configuration changes.
*/
}
}
+ /**
+ * Registers a callback to be executed when the next frame is being drawn on RenderThread. This
+ * callback will be executed on a RenderThread worker thread, and only used for the next frame
+ * and thus it will only fire once.
+ *
+ * @param callback The callback to register.
+ */
+ public void registerRtFrameCallback(FrameDrawingCallback callback) {
+ mNextRtFrameCallback = callback;
+ }
+
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
requestDrawWindow();
}
- mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
+ mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, mNextRtFrameCallback);
+ mNextRtFrameCallback = null;
} else {
// If we get here with a disabled & requested hardware renderer, something went
// wrong (an invalidate posted right before we destroyed the hardware surface
// Grab a copy of everything we need
CanvasContext* context = mContext;
std::function<void(int64_t)> callback = std::move(mFrameCallback);
+ mFrameCallback = nullptr;
// From this point on anything in "this" is *UNSAFE TO ACCESS*
if (canUnblockUiThread) {
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.system;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewRootImpl;
+
+import java.util.ArrayList;
+
+/**
+ * Helper class to apply surface transactions in sync with RenderThread.
+ */
+public class SyncRtSurfaceTransactionApplier {
+
+ private final Object mLock = new Object();
+ private final Surface mTargetSurface;
+ private final ViewRootImpl mTargetViewRootImpl;
+ private final float[] mTmpFloat9 = new float[9];
+
+ /**
+ * @param targetView The view in the surface that acts as synchronization anchor.
+ */
+ public SyncRtSurfaceTransactionApplier(View targetView) {
+ mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
+ mTargetSurface = mTargetViewRootImpl != null ? mTargetViewRootImpl.mSurface : null;
+ }
+
+ /**
+ * Schedules applying surface parameters on the next frame.
+ *
+ * @param params The parameters for the surface to apply.
+ */
+ public void scheduleApply(SurfaceParams params) {
+ ArrayList<SurfaceParams> list = new ArrayList<>(1);
+ list.add(params);
+ scheduleApply(list);
+ }
+
+ /**
+ * Schedules applying surface parameters on the next frame.
+ *
+ * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
+ * this method to avoid synchronization issues.
+ */
+ public void scheduleApply(ArrayList<SurfaceParams> params) {
+ if (mTargetViewRootImpl != null) {
+
+ // Acquire mLock to establish a happens-before relationship to ensure the other thread
+ // sees the surface parameters.
+ synchronized (mLock) {
+ mTargetViewRootImpl.registerRtFrameCallback(frame -> {
+ synchronized (mLock) {
+ if (mTargetSurface == null || !mTargetSurface.isValid()) {
+ return;
+ }
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (int i = params.size() - 1; i >= 0; i--) {
+ SurfaceParams surfaceParams = params.get(i);
+ SurfaceControl surface = surfaceParams.surface;
+ t.deferTransactionUntilSurface(surface, mTargetSurface, frame);
+ t.setMatrix(surface, surfaceParams.matrix, mTmpFloat9);
+ t.setWindowCrop(surface, surfaceParams.windowCrop);
+ t.setAlpha(surface, surfaceParams.alpha);
+ t.setLayer(surface, surfaceParams.layer);
+ t.show(surface);
+ }
+ t.setEarlyWakeup();
+ t.apply();
+ }
+ });
+ }
+ }
+ }
+
+ public static class SurfaceParams {
+
+ /**
+ * Constructs surface parameters to be applied when the current view state gets pushed to
+ * RenderThread.
+ *
+ * @param surface The surface to modify.
+ * @param alpha Alpha to apply.
+ * @param matrix Matrix to apply.
+ * @param windowCrop Crop to apply.
+ */
+ public SurfaceParams(SurfaceControl surface, float alpha, Matrix matrix, Rect windowCrop,
+ int layer) {
+ this.surface = surface;
+ this.alpha = alpha;
+ this.matrix = new Matrix(matrix);
+ this.windowCrop = new Rect(windowCrop);
+ this.layer = layer;
+ }
+
+ final SurfaceControl surface;
+ final float alpha;
+ final Matrix matrix;
+ final Rect windowCrop;
+ final int layer;
+ }
+}
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
-import android.app.ActivityOptions;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.RemoteException;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
-import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.ViewRootImpl;
import com.android.systemui.Interpolators;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationListContainer;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import java.util.ArrayList;
+
/**
* A class that allows activities to be launched in a seamless way where the notification
* transforms nicely into the starting window.
}
AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
- 0 /* statusBarTransitionDelay */);
+ ANIMATION_DURATION - 150 /* statusBarTransitionDelay */);
}
public boolean isAnimationPending() {
private final ExpandableNotificationRow mSourceNotification;
private final ExpandAnimationParameters mParams;
private final Rect mWindowCrop = new Rect();
- private boolean mLeashShown;
private boolean mInstantCollapsePanel = true;
+ private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier;
public AnimationRunner(ExpandableNotificationRow sourceNofitication) {
mSourceNotification = sourceNofitication;
mParams = new ExpandAnimationParameters();
+ mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(mSourceNotification);
}
@Override
}
private void applyParamsToWindow(RemoteAnimationTarget app) {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- if (!mLeashShown) {
- t.show(app.leash);
- mLeashShown = true;
- }
Matrix m = new Matrix();
m.postTranslate(0, (float) (mParams.top - app.position.y));
- t.setMatrix(app.leash, m, new float[9]);
mWindowCrop.set(mParams.left, 0, mParams.right, mParams.getHeight());
- t.setWindowCrop(app.leash, mWindowCrop);
- ViewRootImpl viewRootImpl = mSourceNotification.getViewRootImpl();
- if (viewRootImpl != null) {
- Surface systemUiSurface = viewRootImpl.mSurface;
- t.deferTransactionUntilSurface(app.leash, systemUiSurface,
- systemUiSurface.getNextFrameNumber());
- }
- t.setEarlyWakeup();
- t.apply();
+ SurfaceParams params = new SurfaceParams(app.leash, 1f /* alpha */, m, mWindowCrop,
+ app.prefixOrderIndex);
+ mSyncRtTransactionApplier.scheduleApply(params);
}
@Override