1 /*
2  * Copyright (C) 2015 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.systemui;
18 
19 import android.os.Handler;
20 import android.os.Looper;
21 import android.view.Choreographer;
22 
23 import java.util.ArrayList;
24 
25 /**
26  * Utility class for methods used to dejank the UI.
27  */
28 public class DejankUtils {
29 
30     private static final Choreographer sChoreographer = Choreographer.getInstance();
31     private static final Handler sHandler = new Handler();
32 
33     private static final ArrayList<Runnable> sPendingRunnables = new ArrayList<>();
34 
35     private static final Runnable sAnimationCallbackRunnable = new Runnable() {
36         @Override
37         public void run() {
38             for (int i = 0; i < sPendingRunnables.size(); i++) {
39                 sHandler.post(sPendingRunnables.get(i));
40             }
41             sPendingRunnables.clear();
42         }
43     };
44 
45     /**
46      * Executes {@code r} after performTraversals. Use this do to CPU heavy work for which the
47      * timing is not critical for animation. The work is then scheduled at the same time
48      * RenderThread is doing its thing, leading to better parallelization.
49      *
50      * <p>Needs to be called from the main thread.
51      */
postAfterTraversal(Runnable r)52     public static void postAfterTraversal(Runnable r) {
53         throwIfNotCalledOnMainThread();
54         sPendingRunnables.add(r);
55         postAnimationCallback();
56     }
57 
58     /**
59      * Removes a previously scheduled runnable.
60      *
61      * <p>Needs to be called from the main thread.
62      */
removeCallbacks(Runnable r)63     public static void removeCallbacks(Runnable r) {
64         throwIfNotCalledOnMainThread();
65         sPendingRunnables.remove(r);
66         sHandler.removeCallbacks(r);
67     }
68 
postAnimationCallback()69     private static void postAnimationCallback() {
70         sChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, sAnimationCallbackRunnable,
71                 null);
72     }
73 
throwIfNotCalledOnMainThread()74     private static void throwIfNotCalledOnMainThread() {
75         if (!Looper.getMainLooper().isCurrentThread()) {
76             throw new IllegalStateException("should be called from the main thread.");
77         }
78     }
79 }
80