Merge "Use blast sync for 180 degrees rotation" into udc-dev
This commit is contained in:
@@ -93,6 +93,9 @@ class AsyncRotationController extends FadeAnimationController implements Consume
|
|||||||
/** Whether the start transaction of the transition is committed (by shell). */
|
/** Whether the start transaction of the transition is committed (by shell). */
|
||||||
private boolean mIsStartTransactionCommitted;
|
private boolean mIsStartTransactionCommitted;
|
||||||
|
|
||||||
|
/** Whether all windows should wait for the start transaction. */
|
||||||
|
private boolean mAlwaysWaitForStartTransaction;
|
||||||
|
|
||||||
/** Whether the target windows have been requested to sync their draw transactions. */
|
/** Whether the target windows have been requested to sync their draw transactions. */
|
||||||
private boolean mIsSyncDrawRequested;
|
private boolean mIsSyncDrawRequested;
|
||||||
|
|
||||||
@@ -144,6 +147,15 @@ class AsyncRotationController extends FadeAnimationController implements Consume
|
|||||||
if (mTransitionOp == OP_LEGACY) {
|
if (mTransitionOp == OP_LEGACY) {
|
||||||
mIsStartTransactionCommitted = true;
|
mIsStartTransactionCommitted = true;
|
||||||
} else if (displayContent.mTransitionController.isCollecting(displayContent)) {
|
} else if (displayContent.mTransitionController.isCollecting(displayContent)) {
|
||||||
|
final Transition transition =
|
||||||
|
mDisplayContent.mTransitionController.getCollectingTransition();
|
||||||
|
if (transition != null) {
|
||||||
|
final BLASTSyncEngine.SyncGroup syncGroup =
|
||||||
|
mDisplayContent.mWmService.mSyncEngine.getSyncSet(transition.getSyncId());
|
||||||
|
if (syncGroup != null && syncGroup.mSyncMethod == BLASTSyncEngine.METHOD_BLAST) {
|
||||||
|
mAlwaysWaitForStartTransaction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
keepAppearanceInPreviousRotation();
|
keepAppearanceInPreviousRotation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +214,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
|
|||||||
// target windows. But the windows still need to use sync transaction to keep the appearance
|
// target windows. But the windows still need to use sync transaction to keep the appearance
|
||||||
// in previous rotation, so request a no-op sync to keep the state.
|
// in previous rotation, so request a no-op sync to keep the state.
|
||||||
for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
|
for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
|
||||||
if (mTargetWindowTokens.valueAt(i).canDrawBeforeStartTransaction()) {
|
if (canDrawBeforeStartTransaction(mTargetWindowTokens.valueAt(i))) {
|
||||||
// Expect a screenshot layer will cover the non seamless windows.
|
// Expect a screenshot layer will cover the non seamless windows.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -521,7 +533,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
|
|||||||
if (op == null) return false;
|
if (op == null) return false;
|
||||||
if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w);
|
if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w);
|
||||||
if (postDrawTransaction == null || !mIsSyncDrawRequested
|
if (postDrawTransaction == null || !mIsSyncDrawRequested
|
||||||
|| op.canDrawBeforeStartTransaction()) {
|
|| canDrawBeforeStartTransaction(op)) {
|
||||||
mDisplayContent.finishAsyncRotation(w.mToken);
|
mDisplayContent.finishAsyncRotation(w.mToken);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -563,6 +575,14 @@ class AsyncRotationController extends FadeAnimationController implements Consume
|
|||||||
return super.getFadeOutAnimation();
|
return super.getFadeOutAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the corresponding window can draw its latest content before the
|
||||||
|
* start transaction of rotation transition is applied.
|
||||||
|
*/
|
||||||
|
private boolean canDrawBeforeStartTransaction(Operation op) {
|
||||||
|
return !mAlwaysWaitForStartTransaction && op.mAction != Operation.ACTION_SEAMLESS;
|
||||||
|
}
|
||||||
|
|
||||||
/** The operation to control the rotation appearance associated with window token. */
|
/** The operation to control the rotation appearance associated with window token. */
|
||||||
private static class Operation {
|
private static class Operation {
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@@ -588,14 +608,5 @@ class AsyncRotationController extends FadeAnimationController implements Consume
|
|||||||
Operation(@Action int action) {
|
Operation(@Action int action) {
|
||||||
mAction = action;
|
mAction = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns {@code true} if the corresponding window can draw its latest content before the
|
|
||||||
* start transaction of rotation transition is applied.
|
|
||||||
*/
|
|
||||||
boolean canDrawBeforeStartTransaction() {
|
|
||||||
return TransitionController.SYNC_METHOD != BLASTSyncEngine.METHOD_BLAST
|
|
||||||
&& mAction != ACTION_SEAMLESS;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class BLASTSyncEngine {
|
|||||||
*/
|
*/
|
||||||
class SyncGroup {
|
class SyncGroup {
|
||||||
final int mSyncId;
|
final int mSyncId;
|
||||||
final int mSyncMethod;
|
int mSyncMethod = METHOD_BLAST;
|
||||||
final TransactionReadyListener mListener;
|
final TransactionReadyListener mListener;
|
||||||
final Runnable mOnTimeout;
|
final Runnable mOnTimeout;
|
||||||
boolean mReady = false;
|
boolean mReady = false;
|
||||||
@@ -103,9 +103,8 @@ class BLASTSyncEngine {
|
|||||||
private SurfaceControl.Transaction mOrphanTransaction = null;
|
private SurfaceControl.Transaction mOrphanTransaction = null;
|
||||||
private String mTraceName;
|
private String mTraceName;
|
||||||
|
|
||||||
private SyncGroup(TransactionReadyListener listener, int id, String name, int method) {
|
private SyncGroup(TransactionReadyListener listener, int id, String name) {
|
||||||
mSyncId = id;
|
mSyncId = id;
|
||||||
mSyncMethod = method;
|
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
mOnTimeout = () -> {
|
mOnTimeout = () -> {
|
||||||
Slog.w(TAG, "Sync group " + mSyncId + " timeout");
|
Slog.w(TAG, "Sync group " + mSyncId + " timeout");
|
||||||
@@ -288,13 +287,12 @@ class BLASTSyncEngine {
|
|||||||
* Prepares a {@link SyncGroup} that is not active yet. Caller must call {@link #startSyncSet}
|
* Prepares a {@link SyncGroup} that is not active yet. Caller must call {@link #startSyncSet}
|
||||||
* before calling {@link #addToSyncSet(int, WindowContainer)} on any {@link WindowContainer}.
|
* before calling {@link #addToSyncSet(int, WindowContainer)} on any {@link WindowContainer}.
|
||||||
*/
|
*/
|
||||||
SyncGroup prepareSyncSet(TransactionReadyListener listener, String name, int method) {
|
SyncGroup prepareSyncSet(TransactionReadyListener listener, String name) {
|
||||||
return new SyncGroup(listener, mNextSyncId++, name, method);
|
return new SyncGroup(listener, mNextSyncId++, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name,
|
int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) {
|
||||||
int method) {
|
final SyncGroup s = prepareSyncSet(listener, name);
|
||||||
final SyncGroup s = prepareSyncSet(listener, name, method);
|
|
||||||
startSyncSet(s, timeoutMs);
|
startSyncSet(s, timeoutMs);
|
||||||
return s.mSyncId;
|
return s.mSyncId;
|
||||||
}
|
}
|
||||||
@@ -334,6 +332,15 @@ class BLASTSyncEngine {
|
|||||||
getSyncGroup(id).addToSync(wc);
|
getSyncGroup(id).addToSync(wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSyncMethod(int id, int method) {
|
||||||
|
final SyncGroup syncGroup = getSyncGroup(id);
|
||||||
|
if (!syncGroup.mRootMembers.isEmpty()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Not allow to change sync method after adding group member, id=" + id);
|
||||||
|
}
|
||||||
|
syncGroup.mSyncMethod = method;
|
||||||
|
}
|
||||||
|
|
||||||
void setReady(int id, boolean ready) {
|
void setReady(int id, boolean ready) {
|
||||||
getSyncGroup(id).setReady(ready);
|
getSyncGroup(id).setReady(ready);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -369,7 +369,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
|||||||
return mState;
|
return mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
int getSyncId() {
|
int getSyncId() {
|
||||||
return mSyncId;
|
return mSyncId;
|
||||||
}
|
}
|
||||||
@@ -409,18 +408,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
|||||||
return mState == STATE_FINISHED;
|
return mState == STATE_FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void startCollecting(long timeoutMs) {
|
|
||||||
startCollecting(timeoutMs, TransitionController.SYNC_METHOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Starts collecting phase. Once this starts, all relevant surface operations are sync. */
|
/** Starts collecting phase. Once this starts, all relevant surface operations are sync. */
|
||||||
void startCollecting(long timeoutMs, int method) {
|
void startCollecting(long timeoutMs) {
|
||||||
if (mState != STATE_PENDING) {
|
if (mState != STATE_PENDING) {
|
||||||
throw new IllegalStateException("Attempting to re-use a transition");
|
throw new IllegalStateException("Attempting to re-use a transition");
|
||||||
}
|
}
|
||||||
mState = STATE_COLLECTING;
|
mState = STATE_COLLECTING;
|
||||||
mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG, method);
|
mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG);
|
||||||
|
mSyncEngine.setSyncMethod(mSyncId, TransitionController.SYNC_METHOD);
|
||||||
|
|
||||||
mLogger.mSyncId = mSyncId;
|
mLogger.mSyncId = mSyncId;
|
||||||
mLogger.mCollectTimeNs = SystemClock.elapsedRealtimeNanos();
|
mLogger.mCollectTimeNs = SystemClock.elapsedRealtimeNanos();
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import android.window.TransitionRequestInfo;
|
|||||||
import android.window.WindowContainerTransaction;
|
import android.window.WindowContainerTransaction;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
|
||||||
import com.android.internal.protolog.ProtoLogGroup;
|
import com.android.internal.protolog.ProtoLogGroup;
|
||||||
import com.android.internal.protolog.common.ProtoLog;
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
import com.android.server.FgThread;
|
import com.android.server.FgThread;
|
||||||
@@ -200,12 +199,6 @@ class TransitionController {
|
|||||||
|
|
||||||
/** Starts Collecting */
|
/** Starts Collecting */
|
||||||
void moveToCollecting(@NonNull Transition transition) {
|
void moveToCollecting(@NonNull Transition transition) {
|
||||||
moveToCollecting(transition, SYNC_METHOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Starts Collecting */
|
|
||||||
@VisibleForTesting
|
|
||||||
void moveToCollecting(@NonNull Transition transition, int method) {
|
|
||||||
if (mCollectingTransition != null) {
|
if (mCollectingTransition != null) {
|
||||||
throw new IllegalStateException("Simultaneous transition collection not supported.");
|
throw new IllegalStateException("Simultaneous transition collection not supported.");
|
||||||
}
|
}
|
||||||
@@ -219,7 +212,7 @@ class TransitionController {
|
|||||||
// Distinguish change type because the response time is usually expected to be not too long.
|
// Distinguish change type because the response time is usually expected to be not too long.
|
||||||
final long timeoutMs =
|
final long timeoutMs =
|
||||||
transition.mType == TRANSIT_CHANGE ? CHANGE_TIMEOUT_MS : DEFAULT_TIMEOUT_MS;
|
transition.mType == TRANSIT_CHANGE ? CHANGE_TIMEOUT_MS : DEFAULT_TIMEOUT_MS;
|
||||||
mCollectingTransition.startCollecting(timeoutMs, method);
|
mCollectingTransition.startCollecting(timeoutMs);
|
||||||
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Start collecting in Transition: %s",
|
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Start collecting in Transition: %s",
|
||||||
mCollectingTransition);
|
mCollectingTransition);
|
||||||
dispatchLegacyAppTransitionPending();
|
dispatchLegacyAppTransitionPending();
|
||||||
@@ -492,6 +485,15 @@ class TransitionController {
|
|||||||
} else {
|
} else {
|
||||||
newTransition = requestStartTransition(createTransition(type, flags),
|
newTransition = requestStartTransition(createTransition(type, flags),
|
||||||
trigger != null ? trigger.asTask() : null, remoteTransition, displayChange);
|
trigger != null ? trigger.asTask() : null, remoteTransition, displayChange);
|
||||||
|
if (newTransition != null && displayChange != null && (displayChange.getStartRotation()
|
||||||
|
+ displayChange.getEndRotation()) % 2 == 0) {
|
||||||
|
// 180 degrees rotation change may not change screen size. So the clients may draw
|
||||||
|
// some frames before and after the display projection transaction is applied by the
|
||||||
|
// remote player. That may cause some buffers to show in different rotation. So use
|
||||||
|
// sync method to pause clients drawing until the projection transaction is applied.
|
||||||
|
mAtm.mWindowManager.mSyncEngine.setSyncMethod(newTransition.getSyncId(),
|
||||||
|
BLASTSyncEngine.METHOD_BLAST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (trigger != null) {
|
if (trigger != null) {
|
||||||
if (isExistenceType(type)) {
|
if (isExistenceType(type)) {
|
||||||
|
|||||||
@@ -1648,7 +1648,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
private BLASTSyncEngine.SyncGroup prepareSyncWithOrganizer(
|
private BLASTSyncEngine.SyncGroup prepareSyncWithOrganizer(
|
||||||
IWindowContainerTransactionCallback callback) {
|
IWindowContainerTransactionCallback callback) {
|
||||||
final BLASTSyncEngine.SyncGroup s = mService.mWindowManager.mSyncEngine
|
final BLASTSyncEngine.SyncGroup s = mService.mWindowManager.mSyncEngine
|
||||||
.prepareSyncSet(this, "", BLASTSyncEngine.METHOD_BLAST);
|
.prepareSyncSet(this, "Organizer");
|
||||||
mTransactionCallbacksByPendingSyncId.put(s.mSyncId, callback);
|
mTransactionCallbacksByPendingSyncId.put(s.mSyncId, callback);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
|||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||||
import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST;
|
|
||||||
import static com.android.server.wm.BLASTSyncEngine.METHOD_NONE;
|
import static com.android.server.wm.BLASTSyncEngine.METHOD_NONE;
|
||||||
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
|
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
|
||||||
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||||
@@ -363,7 +362,8 @@ public class SyncEngineTests extends WindowTestsBase {
|
|||||||
BLASTSyncEngine.TransactionReadyListener listener = mock(
|
BLASTSyncEngine.TransactionReadyListener listener = mock(
|
||||||
BLASTSyncEngine.TransactionReadyListener.class);
|
BLASTSyncEngine.TransactionReadyListener.class);
|
||||||
|
|
||||||
int id = startSyncSet(bse, listener, METHOD_NONE);
|
final int id = startSyncSet(bse, listener);
|
||||||
|
bse.setSyncMethod(id, METHOD_NONE);
|
||||||
bse.addToSyncSet(id, mAppWindow.mToken);
|
bse.addToSyncSet(id, mAppWindow.mToken);
|
||||||
mAppWindow.prepareSync();
|
mAppWindow.prepareSync();
|
||||||
assertFalse(mAppWindow.shouldSyncWithBuffers());
|
assertFalse(mAppWindow.shouldSyncWithBuffers());
|
||||||
@@ -373,12 +373,7 @@ public class SyncEngineTests extends WindowTestsBase {
|
|||||||
|
|
||||||
static int startSyncSet(BLASTSyncEngine engine,
|
static int startSyncSet(BLASTSyncEngine engine,
|
||||||
BLASTSyncEngine.TransactionReadyListener listener) {
|
BLASTSyncEngine.TransactionReadyListener listener) {
|
||||||
return startSyncSet(engine, listener, METHOD_BLAST);
|
return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test");
|
||||||
}
|
|
||||||
|
|
||||||
static int startSyncSet(BLASTSyncEngine engine,
|
|
||||||
BLASTSyncEngine.TransactionReadyListener listener, int method) {
|
|
||||||
return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "", method);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TestWindowContainer extends WindowContainer {
|
static class TestWindowContainer extends WindowContainer {
|
||||||
|
|||||||
@@ -1704,7 +1704,8 @@ public class TransitionTests extends WindowTestsBase {
|
|||||||
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
|
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
|
||||||
final Transition transition = new Transition(TRANSIT_OPEN, 0 /* flags */,
|
final Transition transition = new Transition(TRANSIT_OPEN, 0 /* flags */,
|
||||||
app.mTransitionController, mWm.mSyncEngine);
|
app.mTransitionController, mWm.mSyncEngine);
|
||||||
app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
|
app.mTransitionController.moveToCollecting(transition);
|
||||||
|
mWm.mSyncEngine.setSyncMethod(transition.getSyncId(), BLASTSyncEngine.METHOD_NONE);
|
||||||
final ArrayList<WindowContainer> freezeCalls = new ArrayList<>();
|
final ArrayList<WindowContainer> freezeCalls = new ArrayList<>();
|
||||||
transition.setContainerFreezer(new Transition.IContainerFreezer() {
|
transition.setContainerFreezer(new Transition.IContainerFreezer() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1755,7 +1756,8 @@ public class TransitionTests extends WindowTestsBase {
|
|||||||
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
|
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
|
||||||
final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
|
final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
|
||||||
app.mTransitionController, mWm.mSyncEngine);
|
app.mTransitionController, mWm.mSyncEngine);
|
||||||
app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
|
app.mTransitionController.moveToCollecting(transition);
|
||||||
|
mWm.mSyncEngine.setSyncMethod(transition.getSyncId(), BLASTSyncEngine.METHOD_NONE);
|
||||||
final SurfaceControl mockSnapshot = mock(SurfaceControl.class);
|
final SurfaceControl mockSnapshot = mock(SurfaceControl.class);
|
||||||
transition.setContainerFreezer(new Transition.IContainerFreezer() {
|
transition.setContainerFreezer(new Transition.IContainerFreezer() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
|
|||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
|
||||||
import static com.android.server.wm.ActivityRecord.State.RESUMED;
|
import static com.android.server.wm.ActivityRecord.State.RESUMED;
|
||||||
import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST;
|
|
||||||
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||||
import static com.android.server.wm.WindowContainer.SYNC_STATE_READY;
|
import static com.android.server.wm.WindowContainer.SYNC_STATE_READY;
|
||||||
import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION;
|
import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION;
|
||||||
@@ -1001,7 +1000,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
|
|||||||
BLASTSyncEngine.TransactionReadyListener transactionListener =
|
BLASTSyncEngine.TransactionReadyListener transactionListener =
|
||||||
mock(BLASTSyncEngine.TransactionReadyListener.class);
|
mock(BLASTSyncEngine.TransactionReadyListener.class);
|
||||||
|
|
||||||
int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "", METHOD_BLAST);
|
final int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "Test");
|
||||||
bse.addToSyncSet(id, task);
|
bse.addToSyncSet(id, task);
|
||||||
bse.setReady(id);
|
bse.setReady(id);
|
||||||
bse.onSurfacePlacement();
|
bse.onSurfacePlacement();
|
||||||
|
|||||||
Reference in New Issue
Block a user