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.view.View;
20 import android.view.View.OnAttachStateChangeListener;
21 import android.view.ViewTreeObserver.OnDrawListener;
22 
23 import com.android.launcher3.Launcher;
24 
25 import java.util.function.Consumer;
26 
27 /**
28  * An executor which runs all the tasks after the first onDraw is called on the target view.
29  */
30 public class ViewOnDrawExecutor implements OnDrawListener, Runnable,
31         OnAttachStateChangeListener {
32 
33     private final RunnableList mTasks;
34 
35     private Consumer<ViewOnDrawExecutor> mOnClearCallback;
36     private View mAttachedView;
37     private boolean mCompleted;
38 
39     private boolean mLoadAnimationCompleted;
40     private boolean mFirstDrawCompleted;
41 
42     private boolean mCancelled;
43 
ViewOnDrawExecutor(RunnableList tasks)44     public ViewOnDrawExecutor(RunnableList tasks) {
45         mTasks = tasks;
46     }
47 
attachTo(Launcher launcher)48     public void attachTo(Launcher launcher) {
49         mOnClearCallback = launcher::clearPendingExecutor;
50         mAttachedView = launcher.getWorkspace();
51         mAttachedView.addOnAttachStateChangeListener(this);
52 
53         if (mAttachedView.isAttachedToWindow()) {
54             attachObserver();
55         }
56     }
57 
attachObserver()58     private void attachObserver() {
59         if (!mCompleted) {
60             mAttachedView.getViewTreeObserver().addOnDrawListener(this);
61         }
62     }
63 
64     @Override
onViewAttachedToWindow(View v)65     public void onViewAttachedToWindow(View v) {
66         attachObserver();
67     }
68 
69     @Override
onViewDetachedFromWindow(View v)70     public void onViewDetachedFromWindow(View v) {}
71 
72     @Override
onDraw()73     public void onDraw() {
74         mFirstDrawCompleted = true;
75         mAttachedView.post(this);
76     }
77 
onLoadAnimationCompleted()78     public void onLoadAnimationCompleted() {
79         mLoadAnimationCompleted = true;
80         if (mAttachedView != null) {
81             mAttachedView.post(this);
82         }
83     }
84 
85     @Override
run()86     public void run() {
87         // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called.
88         if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) {
89             markCompleted();
90         }
91     }
92 
93     /**
94      * Executes all tasks immediately
95      */
markCompleted()96     public void markCompleted() {
97         if (!mCancelled) {
98             mTasks.executeAllAndDestroy();
99         }
100         mCompleted = true;
101         if (mAttachedView != null) {
102             mAttachedView.getViewTreeObserver().removeOnDrawListener(this);
103             mAttachedView.removeOnAttachStateChangeListener(this);
104         }
105         if (mOnClearCallback != null) {
106             mOnClearCallback.accept(this);
107         }
108     }
109 
cancel()110     public void cancel() {
111         mCancelled = true;
112         markCompleted();
113     }
114 }
115