1 /* 2 * Copyright (C) 2020 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 com.android.server.wm; 18 19 import android.util.ArrayMap; 20 import android.util.ArraySet; 21 22 import java.util.Set; 23 24 /** 25 * Utility class for collecting WindowContainers that will merge transactions. 26 * For example to use to synchronously resize all the children of a window container 27 * 1. Open a new sync set, and pass the listener that will be invoked 28 * int id startSyncSet(TransactionReadyListener) 29 * the returned ID will be eventually passed to the TransactionReadyListener in combination 30 * with a set of WindowContainers that are ready, meaning onTransactionReady was called for 31 * those WindowContainers. You also use it to refer to the operation in future steps. 32 * 2. Ask each child to participate: 33 * addToSyncSet(int id, WindowContainer wc) 34 * if the child thinks it will be affected by a configuration change (a.k.a. has a visible 35 * window in its sub hierarchy, then we will increment a counter of expected callbacks 36 * At this point the containers hierarchy will redirect pendingTransaction and sub hierarchy 37 * updates in to the sync engine. 38 * 3. Apply your configuration changes to the window containers. 39 * 4. Tell the engine that the sync set is ready 40 * setReady(int id) 41 * 5. If there were no sub windows anywhere in the hierarchy to wait on, then 42 * transactionReady is immediately invoked, otherwise all the windows are poked 43 * to redraw and to deliver a buffer to {@link WindowState#finishDrawing}. 44 * Once all this drawing is complete the WindowContainer that's ready will be added to the 45 * set of ready WindowContainers. When the final onTransactionReady is called, it will merge 46 * the transactions of the all the WindowContainers and will be delivered to the 47 * TransactionReadyListener 48 */ 49 class BLASTSyncEngine { 50 private static final String TAG = "BLASTSyncEngine"; 51 52 interface TransactionReadyListener { onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady)53 void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady); 54 }; 55 56 // Holds state associated with a single synchronous set of operations. 57 class SyncState implements TransactionReadyListener { 58 int mSyncId; 59 int mRemainingTransactions; 60 TransactionReadyListener mListener; 61 boolean mReady = false; 62 Set<WindowContainer> mWindowContainersReady = new ArraySet<>(); 63 tryFinish()64 private void tryFinish() { 65 if (mRemainingTransactions == 0 && mReady) { 66 mListener.onTransactionReady(mSyncId, mWindowContainersReady); 67 mPendingSyncs.remove(mSyncId); 68 } 69 } 70 onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady)71 public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) { 72 mRemainingTransactions--; 73 mWindowContainersReady.addAll(windowContainersReady); 74 tryFinish(); 75 } 76 setReady()77 void setReady() { 78 mReady = true; 79 tryFinish(); 80 } 81 addToSync(WindowContainer wc)82 boolean addToSync(WindowContainer wc) { 83 if (wc.prepareForSync(this, mSyncId)) { 84 mRemainingTransactions++; 85 return true; 86 } 87 return false; 88 } 89 SyncState(TransactionReadyListener l, int id)90 SyncState(TransactionReadyListener l, int id) { 91 mListener = l; 92 mSyncId = id; 93 mRemainingTransactions = 0; 94 } 95 }; 96 97 private int mNextSyncId = 0; 98 99 private final ArrayMap<Integer, SyncState> mPendingSyncs = new ArrayMap<>(); 100 BLASTSyncEngine()101 BLASTSyncEngine() { 102 } 103 startSyncSet(TransactionReadyListener listener)104 int startSyncSet(TransactionReadyListener listener) { 105 final int id = mNextSyncId++; 106 final SyncState s = new SyncState(listener, id); 107 mPendingSyncs.put(id, s); 108 return id; 109 } 110 addToSyncSet(int id, WindowContainer wc)111 boolean addToSyncSet(int id, WindowContainer wc) { 112 final SyncState st = mPendingSyncs.get(id); 113 return st.addToSync(wc); 114 } 115 setReady(int id)116 void setReady(int id) { 117 final SyncState st = mPendingSyncs.get(id); 118 st.setReady(); 119 } 120 } 121