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