Files
frameworks_base/tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java
Tianhao Yao 5ecd6d37de Changed setSyncTransaction to syncNextTransaction with callback logic.
Modified SurfaceView and ViewRootImpl to provide callbacks when syncing
a transaction instead of sending transactions. This will ensure a clear
ownership of the transaction object since it will be provided in the
callback when BBQ adds a buffer into the transaction. Modified JNI to
add compatibility for native functions.

Test: Manual testing from go/wm-smoke.
Test: BLASTBufferQueueTest
Bug: 210714235.
Change-Id: I1f872d6b2846b0d64d5b33b8866d0b2ec7126c8c
2022-03-02 09:55:46 -06:00

199 lines
6.7 KiB
Java

/*
* Copyright (C) 2022 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.test;
import android.annotation.NonNull;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.window.SurfaceSyncer;
/**
* Test app that allows the user to resize the SurfaceView and have the new buffer sync with the
* main window. This tests that {@link SurfaceSyncer} is working correctly.
*/
public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.Callback {
private static final String TAG = "SurfaceViewSyncActivity";
private SurfaceView mSurfaceView;
private boolean mLastExpanded = true;
private RenderingThread mRenderingThread;
private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer();
private Button mExpandButton;
private Switch mEnableSyncSwitch;
private int mLastSyncId = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_surfaceview_sync);
mSurfaceView = findViewById(R.id.surface_view);
mSurfaceView.getHolder().addCallback(this);
WindowManager windowManager = getWindowManager();
WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
Rect bounds = metrics.getBounds();
LinearLayout container = findViewById(R.id.container);
mExpandButton = findViewById(R.id.expand_sv);
mEnableSyncSwitch = findViewById(R.id.enable_sync_switch);
mExpandButton.setOnClickListener(view -> updateSurfaceViewSize(bounds, container));
mRenderingThread = new RenderingThread(mSurfaceView.getHolder());
}
private void updateSurfaceViewSize(Rect bounds, View container) {
if (mLastSyncId >= 0) {
return;
}
final float height;
if (mLastExpanded) {
height = bounds.height() / 2f;
mExpandButton.setText("EXPAND SV");
} else {
height = bounds.height() / 1.5f;
mExpandButton.setText("COLLAPSE SV");
}
mLastExpanded = !mLastExpanded;
if (mEnableSyncSwitch.isChecked()) {
mLastSyncId = mSurfaceSyncer.setupSync(() -> { });
mSurfaceSyncer.addToSync(mLastSyncId, container);
}
ViewGroup.LayoutParams svParams = mSurfaceView.getLayoutParams();
svParams.height = (int) height;
mSurfaceView.setLayoutParams(svParams);
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
final Canvas canvas = holder.lockCanvas();
canvas.drawARGB(255, 255, 0, 0);
holder.unlockCanvasAndPost(canvas);
mRenderingThread.startRendering();
mRenderingThread.renderFrame(null, mSurfaceView.getWidth(), mSurfaceView.getHeight());
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
if (mEnableSyncSwitch.isChecked()) {
if (mLastSyncId < 0) {
mRenderingThread.renderFrame(null, width, height);
return;
}
mSurfaceSyncer.addToSync(mLastSyncId, mSurfaceView, frameCallback ->
mRenderingThread.renderFrame(frameCallback, width, height));
mSurfaceSyncer.markSyncReady(mLastSyncId);
mLastSyncId = -1;
} else {
mRenderingThread.renderFrame(null, width, height);
}
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
mRenderingThread.stopRendering();
}
private static class RenderingThread extends HandlerThread {
private final SurfaceHolder mSurfaceHolder;
private Handler mHandler;
private SurfaceSyncer.SurfaceViewFrameCallback mFrameCallback;
private final Point mSurfaceSize = new Point();
int mColorValue = 0;
int mColorDelta = 10;
private final Paint mPaint = new Paint();
RenderingThread(SurfaceHolder holder) {
super("RenderingThread");
mSurfaceHolder = holder;
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(100);
}
public void renderFrame(SurfaceSyncer.SurfaceViewFrameCallback frameCallback, int width,
int height) {
if (mHandler != null) {
mHandler.post(() -> {
mFrameCallback = frameCallback;
mSurfaceSize.set(width, height);
mRunnable.run();
});
}
}
private final Runnable mRunnable = new Runnable() {
@Override
public void run() {
if (mFrameCallback != null) {
mFrameCallback.onFrameStarted();
}
try {
// Long delay from start to finish to mimic slow draw
Thread.sleep(1000);
} catch (InterruptedException e) {
}
mColorValue += mColorDelta;
if (mColorValue > 245 || mColorValue < 10) {
mColorDelta *= -1;
}
Canvas c = mSurfaceHolder.lockCanvas();
c.drawRGB(255, 0, 0);
c.drawText("RENDERED CONTENT", 0, mSurfaceSize.y / 2, mPaint);
mSurfaceHolder.unlockCanvasAndPost(c);
mFrameCallback = null;
}
};
public void startRendering() {
start();
mHandler = new Handler(getLooper());
}
public void stopRendering() {
if (mHandler != null) {
mHandler.removeCallbacks(mRunnable);
}
}
}
}