1 /* 2 * Copyright (C) 2014 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.recents.misc; 18 19 import android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 22 import java.util.ArrayList; 23 24 /** 25 * A ref counted trigger that does some logic when the count is first incremented, or last 26 * decremented. Not thread safe as it's not currently needed. 27 */ 28 public class ReferenceCountedTrigger { 29 30 int mCount; 31 ArrayList<Runnable> mFirstIncRunnables = new ArrayList<>(); 32 ArrayList<Runnable> mLastDecRunnables = new ArrayList<>(); 33 Runnable mErrorRunnable; 34 35 // Convenience runnables 36 Runnable mIncrementRunnable = new Runnable() { 37 @Override 38 public void run() { 39 increment(); 40 } 41 }; 42 Runnable mDecrementRunnable = new Runnable() { 43 @Override 44 public void run() { 45 decrement(); 46 } 47 }; 48 ReferenceCountedTrigger()49 public ReferenceCountedTrigger() { 50 this(null, null, null); 51 } 52 ReferenceCountedTrigger(Runnable firstIncRunnable, Runnable lastDecRunnable, Runnable errorRunanable)53 public ReferenceCountedTrigger(Runnable firstIncRunnable, Runnable lastDecRunnable, 54 Runnable errorRunanable) { 55 if (firstIncRunnable != null) mFirstIncRunnables.add(firstIncRunnable); 56 if (lastDecRunnable != null) mLastDecRunnables.add(lastDecRunnable); 57 mErrorRunnable = errorRunanable; 58 } 59 60 /** Increments the ref count */ increment()61 public void increment() { 62 if (mCount == 0 && !mFirstIncRunnables.isEmpty()) { 63 int numRunnables = mFirstIncRunnables.size(); 64 for (int i = 0; i < numRunnables; i++) { 65 mFirstIncRunnables.get(i).run(); 66 } 67 } 68 mCount++; 69 } 70 71 /** Convenience method to increment this trigger as a runnable */ incrementAsRunnable()72 public Runnable incrementAsRunnable() { 73 return mIncrementRunnable; 74 } 75 76 /** Adds a runnable to the last-decrement runnables list. */ addLastDecrementRunnable(Runnable r)77 public void addLastDecrementRunnable(Runnable r) { 78 mLastDecRunnables.add(r); 79 } 80 81 /** Decrements the ref count */ decrement()82 public void decrement() { 83 mCount--; 84 if (mCount == 0) { 85 flushLastDecrementRunnables(); 86 } else if (mCount < 0) { 87 if (mErrorRunnable != null) { 88 mErrorRunnable.run(); 89 } else { 90 throw new RuntimeException("Invalid ref count"); 91 } 92 } 93 } 94 95 /** 96 * Runs and clears all the last-decrement runnables now. 97 */ flushLastDecrementRunnables()98 public void flushLastDecrementRunnables() { 99 if (!mLastDecRunnables.isEmpty()) { 100 int numRunnables = mLastDecRunnables.size(); 101 for (int i = 0; i < numRunnables; i++) { 102 mLastDecRunnables.get(i).run(); 103 } 104 } 105 mLastDecRunnables.clear(); 106 } 107 108 /** 109 * Convenience method to decrement this trigger as a animator listener. This listener is 110 * guarded to prevent being called back multiple times, and will trigger a decrement once and 111 * only once. 112 */ decrementOnAnimationEnd()113 public Animator.AnimatorListener decrementOnAnimationEnd() { 114 return new AnimatorListenerAdapter() { 115 private boolean hasEnded; 116 117 @Override 118 public void onAnimationEnd(Animator animation) { 119 if (hasEnded) return; 120 decrement(); 121 hasEnded = true; 122 } 123 }; 124 } 125 126 /** Returns the current ref count */ getCount()127 public int getCount() { 128 return mCount; 129 } 130 } 131