• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.launcher3.util;
18 
19 import android.util.Log;
20 import android.view.View;
21 import android.view.View.OnAttachStateChangeListener;
22 import android.view.ViewTreeObserver.OnDrawListener;
23 
24 import com.android.launcher3.Launcher;
25 import com.android.launcher3.testing.shared.TestProtocol;
26 
27 import java.util.function.Consumer;
28 
29 /**
30  * An executor which runs all the tasks after the first onDraw is called on the target view.
31  */
32 public class ViewOnDrawExecutor implements OnDrawListener, Runnable,
33         OnAttachStateChangeListener {
34 
35     private final RunnableList mTasks;
36 
37     private Consumer<ViewOnDrawExecutor> mOnClearCallback;
38     private View mAttachedView;
39     private boolean mCompleted;
40 
41     private boolean mLoadAnimationCompleted;
42     private boolean mFirstDrawCompleted;
43 
44     private boolean mCancelled;
45 
ViewOnDrawExecutor(RunnableList tasks)46     public ViewOnDrawExecutor(RunnableList tasks) {
47         if (TestProtocol.sDebugTracing) {
48             Log.d(TestProtocol.FLAKY_BINDING, "Initialize ViewOnDrawExecutor");
49         }
50         mTasks = tasks;
51     }
52 
attachTo(Launcher launcher)53     public void attachTo(Launcher launcher) {
54         mOnClearCallback = launcher::clearPendingExecutor;
55         mAttachedView = launcher.getWorkspace();
56 
57         if (TestProtocol.sDebugTracing) {
58             Log.d(TestProtocol.FLAKY_BINDING, "ViewOnDrawExecutor.attachTo: launcher=" + launcher
59                     + ", isAttachedToWindow=" + mAttachedView.isAttachedToWindow());
60         }
61 
62         mAttachedView.addOnAttachStateChangeListener(this);
63 
64         if (mAttachedView.isAttachedToWindow()) {
65             attachObserver();
66         }
67     }
68 
attachObserver()69     private void attachObserver() {
70         if (TestProtocol.sDebugTracing) {
71             Log.d(TestProtocol.FLAKY_BINDING,
72                     "ViewOnDrawExecutor.attachObserver: mCompleted=" + mCompleted);
73         }
74         if (!mCompleted) {
75             mAttachedView.getViewTreeObserver().addOnDrawListener(this);
76         }
77     }
78 
79     @Override
onViewAttachedToWindow(View v)80     public void onViewAttachedToWindow(View v) {
81         if (TestProtocol.sDebugTracing) {
82             Log.d(TestProtocol.FLAKY_BINDING, "ViewOnDrawExecutor.onViewAttachedToWindow");
83         }
84         attachObserver();
85     }
86 
87     @Override
onViewDetachedFromWindow(View v)88     public void onViewDetachedFromWindow(View v) {}
89 
90     @Override
onDraw()91     public void onDraw() {
92         if (TestProtocol.sDebugTracing) {
93             Log.d(TestProtocol.FLAKY_BINDING, "ViewOnDrawExecutor.onDraw");
94         }
95         mFirstDrawCompleted = true;
96         mAttachedView.post(this);
97     }
98 
onLoadAnimationCompleted()99     public void onLoadAnimationCompleted() {
100         if (TestProtocol.sDebugTracing) {
101             Log.d(TestProtocol.FLAKY_BINDING,
102                     "ViewOnDrawExecutor.onLoadAnimationCompleted: mAttachedView != null="
103                             + (mAttachedView != null));
104         }
105         mLoadAnimationCompleted = true;
106         if (mAttachedView != null) {
107             mAttachedView.post(this);
108         }
109     }
110 
111     @Override
run()112     public void run() {
113         if (TestProtocol.sDebugTracing) {
114             Log.d(TestProtocol.FLAKY_BINDING,
115                     "ViewOnDrawExecutor.run: mLoadAnimationCompleted=" + mLoadAnimationCompleted
116                             + ", mFirstDrawCompleted=" + mFirstDrawCompleted
117                             + ", mCompleted=" + mCompleted);
118         }
119         // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called.
120         if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) {
121             markCompleted();
122         }
123     }
124 
125     /**
126      * Executes all tasks immediately
127      */
markCompleted()128     public void markCompleted() {
129         if (TestProtocol.sDebugTracing) {
130             Log.d(TestProtocol.FLAKY_BINDING,
131                     "ViewOnDrawExecutor.markCompleted: mCancelled=" + mCancelled
132                             + ", mOnClearCallback != null=" + (mOnClearCallback != null)
133                             + ", mAttachedView != null=" + (mAttachedView != null));
134         }
135         if (!mCancelled) {
136             mTasks.executeAllAndDestroy();
137         }
138         mCompleted = true;
139         if (mAttachedView != null) {
140             mAttachedView.getViewTreeObserver().removeOnDrawListener(this);
141             mAttachedView.removeOnAttachStateChangeListener(this);
142         }
143         if (mOnClearCallback != null) {
144             mOnClearCallback.accept(this);
145         }
146     }
147 
cancel()148     public void cancel() {
149         if (TestProtocol.sDebugTracing) {
150             Log.d(TestProtocol.FLAKY_BINDING, "ViewOnDrawExecutor.cancel");
151         }
152         mCancelled = true;
153         markCompleted();
154     }
155 }
156