/*
* Copyright (C) 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.apps.santatracker.doodles.shared;
import java.util.ArrayList;
import java.util.List;
/**
* Manages a list of tweens, taking care of removing them when they are done, and adding them (even
* in the middle of iterating over the list of tweens).
*/
public class TweenManager {
private final List<Tween> tweens = new ArrayList<>();
private final List<Tween> incomingTweens = new ArrayList<>();
private boolean shouldRemoveAll = false;
public void update(float deltaMs) {
// First, check whether removeAll was called since the last update.
if (shouldRemoveAll) {
finishRemovingAll();
return;
}
try {
// Move everything from incomingTweens to tweens (before iterating over tweens)
for (int i = 0; i < incomingTweens.size(); i++) { // Avoiding iterator to avoid garbage.
tweens.add(incomingTweens.get(i));
}
incomingTweens.clear();
// Now iterate through tweens.
for (int i = tweens.size() - 1; i >= 0; i--) { // Avoiding iterator to avoid garbage.
Tween tween = tweens.get(i);
boolean finished = tween == null || !tween.update(deltaMs);
if (shouldRemoveAll) {
finishRemovingAll();
return;
}
if (finished) {
tweens.remove(i);
}
}
} catch (Exception e) { // do nothing
}
}
public void add(Tween tween) {
if (tween.durationSeconds() < 0) {
throw new IllegalArgumentException("Tween duration should not be negative");
}
// Don't add to main list of tweens directly, to avoid ConcurrentModificationException.
incomingTweens.add(tween);
}
/**
* Removes all the tweens at the next possible opportunity. This isn't synchronous, but will
* happen before any more tween.update calls occur.
*/
public void removeAll() {
// Remove incoming tweens immediately. No risk of removing while iterating for these, and we
// shouldn't clear this later in finishRemovingAll in case more have been added since then,
// so clear immediately.
incomingTweens.clear();
// There is a risk of removing while iterating for tweens though, so set a flag instead of
// immediately clearing it.
shouldRemoveAll = true;
}
private void finishRemovingAll() {
// Don't clear incomingTweens here, on the assumption that A) removeAll already cleared it
// and B) there's a possibility more have been added since then, and they *shouldn't* get
// cleared.
tweens.clear();
shouldRemoveAll = false;
}
}