Merge "Fix a memory leak" into sc-dev
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index f4ef1f7..c91fa9f 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
-import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -97,8 +96,8 @@
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.InputConsumerProxy;
+import com.android.quickstep.util.InputProxyHandlerFactory;
import com.android.quickstep.util.MotionPauseDetector;
-import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.ProtoTracer;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.RectFSpringAnim;
@@ -113,12 +112,10 @@
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TaskInfoCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.function.Consumer;
/**
@@ -255,7 +252,10 @@
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumerProxy =
- new InputConsumerProxy(inputConsumer, this::createNewInputProxyHandler);
+ new InputConsumerProxy(inputConsumer, () -> {
+ endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
+ endLauncherTransitionController();
+ }, new InputProxyHandlerFactory(mActivityInterface, mGestureState));
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
@@ -783,19 +783,6 @@
handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);
}
- /**
- * Called to create a input proxy for the running task
- */
- @UiThread
- protected InputConsumer createNewInputProxyHandler() {
- endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
- endLauncherTransitionController();
-
- StatefulActivity activity = mActivityInterface.getCreatedActivity();
- return activity == null ? InputConsumer.NO_OP
- : new OverviewInputConsumer(mGestureState, activity, null, true);
- }
-
private void endRunningWindowAnim(boolean cancel) {
if (mRunningWindowAnim != null) {
if (cancel) {
@@ -1338,6 +1325,7 @@
mInputConsumerProxy.destroy();
mTaskAnimationManager.setLiveTileCleanUpHandler(null);
}
+ mInputConsumerProxy.unregisterCallback();
endRunningWindowAnim(false /* cancel */);
if (mGestureEndCallback != null) {
@@ -1502,36 +1490,13 @@
protected abstract void finishRecentsControllerToHome(Runnable callback);
- private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (mRecentsView.getRunningTaskIndex() != -1
- && mRecentsView.getRunningTaskId() == task.taskId
- && mRecentsAnimationTargets.hasTask(task.taskId)) {
- launchOtherTaskInLiveTileMode(task.taskId, mRecentsAnimationTargets.apps);
- }
- ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
- mLiveTileRestartListener);
- }
- };
-
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
mActivityInterface.onSwipeUpToRecentsComplete();
mRecentsView.onSwipeUpAnimationSuccess();
if (LIVE_TILE.get()) {
- mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler(
- appearedTaskTarget -> {
- RemoteAnimationTargetCompat[] apps = Arrays.copyOf(
- mRecentsAnimationTargets.apps,
- mRecentsAnimationTargets.apps.length + 1);
- apps[apps.length - 1] = appearedTaskTarget;
- launchOtherTaskInLiveTileMode(appearedTaskTarget.taskId, apps);
- });
mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy);
- ActivityManagerWrapper.getInstance().registerTaskStackListener(
- mLiveTileRestartListener);
+ mTaskAnimationManager.enableLiveTileRestartListener();
}
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
@@ -1539,65 +1504,6 @@
reset();
}
- private void launchOtherTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) {
- AnimatorSet anim = new AnimatorSet();
- TaskView taskView = mRecentsView.getTaskView(taskId);
- if (taskView == null || !mRecentsView.isTaskViewVisible(taskView)) {
- // TODO: Refine this animation.
- SurfaceTransactionApplier surfaceApplier =
- new SurfaceTransactionApplier(mActivity.getDragLayer());
- ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
- appAnimator.setDuration(RECENTS_LAUNCH_DURATION);
- appAnimator.setInterpolator(ACCEL_DEACCEL);
- appAnimator.addUpdateListener(new MultiValueUpdateListener() {
- @Override
- public void onUpdate(float percent) {
- SurfaceParams.Builder builder = new SurfaceParams.Builder(
- apps[apps.length - 1].leash);
- Matrix matrix = new Matrix();
- matrix.postScale(percent, percent);
- matrix.postTranslate(mDp.widthPx * (1 - percent) / 2,
- mDp.heightPx * (1 - percent) / 2);
- builder.withAlpha(percent).withMatrix(matrix);
- surfaceApplier.scheduleApply(builder.build());
- }
- });
- anim.play(appAnimator);
- } else {
- TaskViewUtils.composeRecentsLaunchAnimator(
- anim, taskView, apps,
- mRecentsAnimationTargets.wallpapers, true /* launcherClosing */,
- mActivity.getStateManager(), mRecentsView,
- mActivityInterface.getDepthController());
- }
- anim.addListener(new AnimatorListenerAdapter(){
-
- @Override
- public void onAnimationEnd(Animator animator) {
- cleanUp(false);
- }
-
- @Override
- public void onAnimationCancel(Animator animator) {
- cleanUp(true);
- }
-
- private void cleanUp(boolean canceled) {
- if (mRecentsAnimationController != null) {
- mRecentsAnimationController.finish(false /* toRecents */,
- null /* onFinishComplete */);
- if (canceled) {
- mRecentsAnimationController = null;
- } else {
- mActivityInterface.onLaunchTaskSuccess();
- }
- ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
- }
- }
- });
- anim.start();
- }
-
private static boolean isNotInRecents(RemoteAnimationTargetCompat app) {
return app.isNotInRecents
|| app.activityType == ACTIVITY_TYPE_HOME;
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index da0a664..718c5ba 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -41,13 +41,4 @@
public boolean hasTargets() {
return unfilteredApps.length != 0;
}
-
- public boolean hasTask(int taskId) {
- for (RemoteAnimationTargetCompat target : unfilteredApps) {
- if (target.taskId == taskId) {
- return true;
- }
- }
- return false;
- }
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 9a454f2..b6dad2d 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -17,10 +17,11 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -31,13 +32,13 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.RemoteTransitionCompat;
-
-import java.util.function.Consumer;
+import com.android.systemui.shared.system.TaskStackChangeListener;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
public static final boolean ENABLE_SHELL_TRANSITIONS =
@@ -49,10 +50,24 @@
// Temporary until we can hook into gesture state events
private GestureState mLastGestureState;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
- private Consumer<RemoteAnimationTargetCompat> mLaunchOtherTaskHandler;
private Runnable mLiveTileCleanUpHandler;
private Context mCtx;
+ private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
+ if (LIVE_TILE.get() && activityInterface.isInLiveTileMode()
+ && activityInterface.getCreatedActivity() != null) {
+ RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel();
+ recentsView.launchSideTaskInLiveTileModeForRestartedApp(task.taskId);
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
+ mLiveTileRestartListener);
+ }
+ }
+ };
+
TaskAnimationManager(Context ctx) {
mCtx = ctx;
}
@@ -114,9 +129,14 @@
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
- if (mLaunchOtherTaskHandler != null
- && mLastGestureState.getEndTarget() == RECENTS) {
- mLaunchOtherTaskHandler.accept(appearedTaskTarget);
+ BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
+ if (LIVE_TILE.get() && activityInterface.isInLiveTileMode()
+ && activityInterface.getCreatedActivity() != null) {
+ RecentsView recentsView =
+ activityInterface.getCreatedActivity().getOverviewPanel();
+ RemoteAnimationTargetCompat[] apps = new RemoteAnimationTargetCompat[1];
+ apps[0] = appearedTaskTarget;
+ recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, apps);
return;
}
if (mController != null) {
@@ -161,17 +181,12 @@
return mCallbacks;
}
- /**
- * The passed-in handler is used to render side task launch animation in recents in live tile
- * mode.
- */
- public void setLaunchOtherTaskInLiveTileModeHandler(
- Consumer<RemoteAnimationTargetCompat> handler) {
- mLaunchOtherTaskHandler = handler;
+ public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) {
+ mLiveTileCleanUpHandler = cleanUpHandler;
}
- public void setLiveTileCleanUpHandler(Runnable runnable) {
- mLiveTileCleanUpHandler = runnable;
+ public void enableLiveTileRestartListener() {
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mLiveTileRestartListener);
}
/**
@@ -215,6 +230,7 @@
mLiveTileCleanUpHandler.run();
mLiveTileCleanUpHandler = null;
}
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mLiveTileRestartListener);
// Release all the target leashes
if (mTargets != null) {
@@ -231,7 +247,6 @@
mTargets = null;
mLastGestureState = null;
mLastAppearedTaskTarget = null;
- mLaunchOtherTaskHandler = null;
}
public void dump() {
diff --git a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
index 3e87f48..2e5b33a 100644
--- a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
@@ -38,7 +38,8 @@
private static final String TAG = "InputConsumerProxy";
private final InputConsumerController mInputConsumerController;
- private final Supplier<InputConsumer> mConsumerSupplier;
+ private Runnable mCallback;
+ private Supplier<InputConsumer> mConsumerSupplier;
// The consumer is created lazily on demand.
private InputConsumer mInputConsumer;
@@ -48,8 +49,9 @@
private boolean mDestroyPending = false;
public InputConsumerProxy(InputConsumerController inputConsumerController,
- Supplier<InputConsumer> consumerSupplier) {
+ Runnable callback, Supplier<InputConsumer> consumerSupplier) {
mInputConsumerController = inputConsumerController;
+ mCallback = callback;
mConsumerSupplier = consumerSupplier;
}
@@ -64,9 +66,7 @@
if (ev instanceof MotionEvent) {
onInputConsumerMotionEvent((MotionEvent) ev);
} else if (ev instanceof KeyEvent) {
- if (mInputConsumer == null) {
- mInputConsumer = mConsumerSupplier.get();
- }
+ initInputConsumerIfNeeded();
mInputConsumer.onKeyEvent((KeyEvent) ev);
return true;
}
@@ -89,9 +89,7 @@
if (action == ACTION_DOWN) {
mTouchInProgress = true;
- if (mInputConsumer == null) {
- mInputConsumer = mConsumerSupplier.get();
- }
+ initInputConsumerIfNeeded();
} else if (action == ACTION_CANCEL || action == ACTION_UP) {
// Finish any pending actions
mTouchInProgress = false;
@@ -115,4 +113,18 @@
mDestroyed = true;
mInputConsumerController.setInputListener(null);
}
+
+ public void unregisterCallback() {
+ mCallback = null;
+ }
+
+ private void initInputConsumerIfNeeded() {
+ if (mInputConsumer == null) {
+ if (mCallback != null) {
+ mCallback.run();
+ }
+ mInputConsumer = mConsumerSupplier.get();
+ mConsumerSupplier = null;
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
new file mode 100644
index 0000000..8209c09
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * 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.android.quickstep.util;
+
+import androidx.annotation.UiThread;
+
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.inputconsumers.OverviewInputConsumer;
+
+import java.util.function.Supplier;
+
+/**
+ * A factory that creates a input consumer for
+ * {@link com.android.quickstep.util.InputConsumerProxy}.
+ */
+public class InputProxyHandlerFactory implements Supplier<InputConsumer> {
+
+ private final BaseActivityInterface mActivityInterface;
+ private final GestureState mGestureState;
+
+ @UiThread
+ public InputProxyHandlerFactory(BaseActivityInterface activityInterface,
+ GestureState gestureState) {
+ mActivityInterface = activityInterface;
+ mGestureState = gestureState;
+ }
+
+ /**
+ * Called to create a input proxy for the running task
+ */
+ @Override
+ public InputConsumer get() {
+ StatefulActivity activity = mActivityInterface.getCreatedActivity();
+ return activity == null ? InputConsumer.NO_OP
+ : new OverviewInputConsumer(mGestureState, activity, null, true);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index d357ebe..7693440 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -27,6 +27,7 @@
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
+import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
@@ -34,6 +35,7 @@
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
@@ -50,6 +52,7 @@
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
@@ -61,6 +64,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -129,8 +133,11 @@
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
+import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.ViewUtils;
+import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.quickstep.util.SurfaceTransactionApplier;
@@ -142,6 +149,8 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.wm.shell.pip.IPipAnimationListener;
@@ -715,6 +724,72 @@
super.draw(canvas);
}
+ public void launchSideTaskInLiveTileModeForRestartedApp(int taskId) {
+ if (mRunningTaskId != -1 && mRunningTaskId == taskId &&
+ getLiveTileParams().getTargetSet().findTask(taskId) != null) {
+ launchSideTaskInLiveTileMode(taskId, getLiveTileParams().getTargetSet().apps);
+ }
+ }
+
+ public void launchSideTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) {
+ AnimatorSet anim = new AnimatorSet();
+ TaskView taskView = getTaskView(taskId);
+ if (taskView == null || !isTaskViewVisible(taskView)) {
+ // TODO: Refine this animation.
+ SurfaceTransactionApplier surfaceApplier =
+ new SurfaceTransactionApplier(mActivity.getDragLayer());
+ ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
+ appAnimator.setDuration(RECENTS_LAUNCH_DURATION);
+ appAnimator.setInterpolator(ACCEL_DEACCEL);
+ appAnimator.addUpdateListener(new MultiValueUpdateListener() {
+ @Override
+ public void onUpdate(float percent) {
+ SurfaceParams.Builder builder = new SurfaceParams.Builder(
+ apps[apps.length - 1].leash);
+ Matrix matrix = new Matrix();
+ matrix.postScale(percent, percent);
+ matrix.postTranslate(mActivity.getDeviceProfile().widthPx * (1 - percent) / 2,
+ mActivity.getDeviceProfile().heightPx * (1 - percent) / 2);
+ builder.withAlpha(percent).withMatrix(matrix);
+ surfaceApplier.scheduleApply(builder.build());
+ }
+ });
+ anim.play(appAnimator);
+ } else {
+ TaskViewUtils.composeRecentsLaunchAnimator(
+ anim, taskView, apps,
+ mLiveTileParams.getTargetSet().wallpapers, true /* launcherClosing */,
+ mActivity.getStateManager(), this,
+ getDepthController());
+ }
+ anim.addListener(new AnimatorListenerAdapter(){
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ cleanUp(false);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ cleanUp(true);
+ }
+
+ private void cleanUp(boolean canceled) {
+ if (mRecentsAnimationController != null) {
+ mRecentsAnimationController.finish(false /* toRecents */,
+ null /* onFinishComplete */);
+ if (canceled) {
+ mRecentsAnimationController = null;
+ } else {
+ mSizeStrategy.onLaunchTaskSuccess();
+ }
+ ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
+ }
+ }
+ });
+ anim.start();
+ }
+
private void updateTaskStartIndex(View affectingView) {
if (!(affectingView instanceof TaskView) && !(affectingView instanceof ClearAllButton)) {
int childCount = getChildCount();