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.os.Process; 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.LauncherModel; 26 27 import java.util.ArrayList; 28 import java.util.concurrent.Executor; 29 30 /** 31 * An executor which runs all the tasks after the first onDraw is called on the target view. 32 */ 33 public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, 34 OnAttachStateChangeListener { 35 36 private final ArrayList<Runnable> mTasks = new ArrayList<>(); 37 38 private Launcher mLauncher; 39 private View mAttachedView; 40 private boolean mCompleted; 41 42 private boolean mLoadAnimationCompleted; 43 private boolean mFirstDrawCompleted; 44 attachTo(Launcher launcher)45 public void attachTo(Launcher launcher) { 46 attachTo(launcher, launcher.getWorkspace(), true /* waitForLoadAnimation */); 47 } 48 attachTo(Launcher launcher, View attachedView, boolean waitForLoadAnimation)49 public void attachTo(Launcher launcher, View attachedView, boolean waitForLoadAnimation) { 50 mLauncher = launcher; 51 mAttachedView = attachedView; 52 mAttachedView.addOnAttachStateChangeListener(this); 53 if (!waitForLoadAnimation) { 54 mLoadAnimationCompleted = true; 55 } 56 57 attachObserver(); 58 } 59 attachObserver()60 private void attachObserver() { 61 if (!mCompleted) { 62 mAttachedView.getViewTreeObserver().addOnDrawListener(this); 63 } 64 } 65 66 @Override execute(Runnable command)67 public void execute(Runnable command) { 68 mTasks.add(command); 69 LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_BACKGROUND); 70 } 71 72 @Override onViewAttachedToWindow(View v)73 public void onViewAttachedToWindow(View v) { 74 attachObserver(); 75 } 76 77 @Override onViewDetachedFromWindow(View v)78 public void onViewDetachedFromWindow(View v) {} 79 80 @Override onDraw()81 public void onDraw() { 82 mFirstDrawCompleted = true; 83 mAttachedView.post(this); 84 } 85 onLoadAnimationCompleted()86 public void onLoadAnimationCompleted() { 87 mLoadAnimationCompleted = true; 88 if (mAttachedView != null) { 89 mAttachedView.post(this); 90 } 91 } 92 93 @Override run()94 public void run() { 95 // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called. 96 if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) { 97 runAllTasks(); 98 } 99 } 100 markCompleted()101 public void markCompleted() { 102 mTasks.clear(); 103 mCompleted = true; 104 if (mAttachedView != null) { 105 mAttachedView.getViewTreeObserver().removeOnDrawListener(this); 106 mAttachedView.removeOnAttachStateChangeListener(this); 107 } 108 if (mLauncher != null) { 109 mLauncher.clearPendingExecutor(this); 110 } 111 LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_DEFAULT); 112 } 113 isCompleted()114 protected boolean isCompleted() { 115 return mCompleted; 116 } 117 runAllTasks()118 protected void runAllTasks() { 119 for (final Runnable r : mTasks) { 120 r.run(); 121 } 122 markCompleted(); 123 } 124 } 125