Updating swipe up on home animations

> Scaling down home activity on swipe-up from home and spring back to place on cancel
> Fading out recents on swipe-up to home, so ensure that adjecent tiles also dissapear
> Instead of controlling alpha, controlling full transform for base and home task. This allows adding custom animation for home task on swipe up.
> Removing alpha hanging for fallback activity in baseSwipeHandler. Instead controlling full transform for home activity
> Adding feature flag to use QuickstepLauncher as 3P Launcher to make development easier.

Bug: 156398988
Change-Id: I69cc59f2c9c95d15df6926ba635e7d6c251dceb6
This commit is contained in:
Sunny Goyal
2020-05-20 20:34:04 -07:00
parent 32f6cd1116
commit a314d5ad58
12 changed files with 163 additions and 91 deletions
@@ -136,10 +136,13 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
new SyncRtSurfaceTransactionApplierCompat(mActivity.getRootView()));
AnimatedFloat recentsAlpha = new AnimatedFloat(() -> { });
params.setBaseAlphaCallback((t, a) -> recentsAlpha.value);
params.setBaseBuilderProxy((builder, app, p)
-> builder.withAlpha(recentsAlpha.value));
Interpolator taskInterpolator;
if (targets.isAnimatingHome()) {
params.setHomeBuilderProxy((builder, app, p) -> builder.withAlpha(1 - p.getProgress()));
taskInterpolator = TOUCH_RESPONSE_INTERPOLATOR;
pa.addFloat(recentsAlpha, AnimatedFloat.VALUE, 0, 1, TOUCH_RESPONSE_INTERPOLATOR);
} else {
@@ -73,7 +73,6 @@ import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
import com.android.quickstep.util.TransformParams.TargetAlphaProvider;
import com.android.quickstep.views.LiveTileOverlay;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -671,10 +670,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
protected InputConsumer createNewInputProxyHandler() {
endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
endLauncherTransitionController();
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// Hide the task view, if not already hidden
setTargetAlphaProvider(BaseSwipeUpHandlerV2::getHiddenTargetAlpha);
}
StatefulActivity activity = mActivityInterface.getCreatedActivity();
return activity == null ? InputConsumer.NO_OP
@@ -1257,11 +1252,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
reset();
}
private void setTargetAlphaProvider(TargetAlphaProvider provider) {
mTransformParams.setTaskAlphaCallback(provider);
updateFinalShift();
}
private void addLiveTileOverlay() {
if (LiveTileOverlay.INSTANCE.attach(mActivity.getRootView().getOverlay())) {
mRecentsView.setLiveTileOverlayAttached(true);
@@ -1273,13 +1263,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
mRecentsView.setLiveTileOverlayAttached(false);
}
public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, float expectedAlpha) {
if (!isNotInRecents(app)) {
return 0;
}
return expectedAlpha;
}
private static boolean isNotInRecents(RemoteAnimationTargetCompat app) {
return app.isNotInRecents
|| app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -15,23 +15,29 @@
*/
package com.android.quickstep;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import android.animation.ObjectAnimator;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.graphics.Matrix;
import androidx.annotation.NonNull;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
/**
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
@@ -42,6 +48,9 @@ public class FallbackSwipeHandler extends
private FallbackHomeAnimationFactory mActiveAnimationFactory;
private final boolean mRunningOverHome;
private final Matrix mTmpMatrix = new Matrix();
private float mMaxLauncherScale = 1;
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer) {
@@ -49,6 +58,31 @@ public class FallbackSwipeHandler extends
continuingLastGesture, inputConsumer);
mRunningOverHome = ActivityManagerWrapper.isHomeTask(mGestureState.getRunningTask());
if (mRunningOverHome) {
mTransformParams.setHomeBuilderProxy(this::updateHomeActivityTransformDuringSwipeUp);
}
}
@Override
protected void initTransitionEndpoints(DeviceProfile dp) {
super.initTransitionEndpoints(dp);
if (mRunningOverHome) {
mMaxLauncherScale = 1 / mTaskViewSimulator.getFullScreenScale();
}
}
private void updateHomeActivityTransformDuringSwipeUp(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params) {
setHomeScaleAndAlpha(builder, app, mCurrentShift.value,
Utilities.boundToRange(1 - mCurrentShift.value, 0, 1));
}
private void setHomeScaleAndAlpha(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, float verticalShift, float alpha) {
float scale = Utilities.mapRange(verticalShift, 1, mMaxLauncherScale);
mTmpMatrix.setScale(scale, scale,
app.localBounds.exactCenterX(), app.localBounds.exactCenterY());
builder.withMatrix(mTmpMatrix).withAlpha(alpha);
}
@Override
@@ -85,30 +119,61 @@ public class FallbackSwipeHandler extends
}
}
private class FallbackHomeAnimationFactory extends HomeAnimationFactory
implements TransformParams.BuilderProxy {
private class FallbackHomeAnimationFactory extends HomeAnimationFactory {
private final TransformParams mHomeAlphaParams = new TransformParams();
private final AnimatedFloat mHomeAlpha = new AnimatedFloat(this::updateHomeAlpha);
private final AnimatedFloat mHomeAlpha;
private final AnimatedFloat mVerticalShiftForScale = new AnimatedFloat();
private final AnimatedFloat mRecentsAlpha = new AnimatedFloat();
private final long mDuration;
FallbackHomeAnimationFactory(long duration) {
super(null);
mDuration = duration;
if (mRunningOverHome) {
mHomeAlpha = new AnimatedFloat();
mHomeAlpha.value = Utilities.boundToRange(1 - mCurrentShift.value, 0, 1);
mVerticalShiftForScale.value = mCurrentShift.value;
mTransformParams.setHomeBuilderProxy(
this::updateHomeActivityTransformDuringHomeAnim);
} else {
mHomeAlpha = new AnimatedFloat(this::updateHomeAlpha);
mHomeAlpha.value = 0;
mHomeAlphaParams.setHomeBuilderProxy(
this::updateHomeActivityTransformDuringHomeAnim);
}
mRecentsAlpha.value = 1;
mTransformParams.setBaseBuilderProxy(
this::updateRecentsActivityTransformDuringHomeAnim);
}
private void updateRecentsActivityTransformDuringHomeAnim(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params) {
builder.withAlpha(mRecentsAlpha.value);
}
private void updateHomeActivityTransformDuringHomeAnim(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params) {
setHomeScaleAndAlpha(builder, app, mVerticalShiftForScale.value, mHomeAlpha.value);
}
@NonNull
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
PendingAnimation pa = new PendingAnimation(mDuration);
pa.setFloat(mHomeAlpha, AnimatedFloat.VALUE, 1, LINEAR);
pa.setFloat(mRecentsAlpha, AnimatedFloat.VALUE, 0, ACCEL);
return pa.createPlaybackController();
}
private void updateHomeAlpha() {
mHomeAlphaParams.setProgress(mHomeAlpha.value);
if (mHomeAlphaParams.getTargetSet() != null) {
mHomeAlphaParams.applySurfaceParams(mHomeAlphaParams.createSurfaceParams(this));
mHomeAlphaParams.applySurfaceParams(
mHomeAlphaParams.createSurfaceParams(BuilderProxy.NO_OP));
}
}
@@ -125,7 +190,23 @@ public class FallbackSwipeHandler extends
}
@Override
public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app, int targetMode,
TransformParams params) { }
public void playAtomicAnimation(float velocity) {
ObjectAnimator alphaAnim = mHomeAlpha.animateToValue(mHomeAlpha.value, 1);
alphaAnim.setDuration(mDuration).setInterpolator(ACCEL);
alphaAnim.start();
if (mRunningOverHome) {
// Spring back launcher scale
new SpringAnimationBuilder(mContext)
.setStartValue(mVerticalShiftForScale.value)
.setEndValue(0)
.setStartVelocity(-velocity / mTransitionDragLength)
.setMinimumVisibleChange(1f / mDp.heightPx)
.setDampingRatio(0.6f)
.setStiffness(800)
.build(mVerticalShiftForScale, AnimatedFloat.VALUE)
.start();
}
}
}
}
@@ -34,7 +34,6 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.View;
@@ -51,7 +50,6 @@ import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
@@ -62,7 +60,6 @@ import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@@ -77,8 +74,6 @@ import java.io.PrintWriter;
*/
public final class RecentsActivity extends StatefulActivity<RecentsState> {
public static final String EXTRA_THUMBNAIL = "thumbnailData";
public static final String EXTRA_TASK_ID = "taskID";
public static final ActivityTracker<RecentsActivity> ACTIVITY_TRACKER =
new ActivityTracker<>();
@@ -118,21 +113,6 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
@Override
protected void onNewIntent(Intent intent) {
if (intent.getExtras() != null) {
int taskID = intent.getIntExtra(EXTRA_TASK_ID, 0);
IBinder thumbnail = intent.getExtras().getBinder(EXTRA_THUMBNAIL);
if (taskID != 0 && thumbnail instanceof ObjectWrapper) {
ObjectWrapper<ThumbnailData> obj = (ObjectWrapper<ThumbnailData>) thumbnail;
ThumbnailData thumbnailData = obj.get();
mFallbackRecentsView.showCurrentTask(taskID);
mFallbackRecentsView.updateThumbnail(taskID, thumbnailData);
// Clear the ref since any reference to the extras on the system side will still
// hold a reference to the wrapper
obj.clear();
}
}
intent.removeExtra(EXTRA_TASK_ID);
intent.removeExtra(EXTRA_THUMBNAIL);
super.onNewIntent(intent);
ACTIVITY_TRACKER.handleNewIntent(this, intent);
}
@@ -143,9 +143,6 @@ public final class TaskViewUtils {
boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage();
int startScroll = recentsView.getScrollOffset(taskIndex);
params.setProgress(1);
out.setFloat(params, TransformParams.PROGRESS, 0, TOUCH_RESPONSE_INTERPOLATOR);
Context context = v.getContext();
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
// RecentsView never updates the display rotation until swipe-up so the value may be stale.
@@ -173,9 +170,7 @@ public final class TaskViewUtils {
}
// Fade in the task during the initial 20% of the animation
AnimatedFloat taskAlpha = new AnimatedFloat(() -> { });
params.setTaskAlphaCallback((t, alpha) -> taskAlpha.value);
out.addFloat(taskAlpha, AnimatedFloat.VALUE, 0, 1, clampToProgress(LINEAR, 0, 0.2f));
out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1, clampToProgress(LINEAR, 0, 0.2f));
if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulator != null) {
out.addFloat(v, VIEW_ALPHA, 1, 0, clampToProgress(LINEAR, 0.2f, 0.4f));
@@ -87,8 +87,8 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
private float mCurveScale = 1;
// RecentsView properties
public final AnimatedFloat recentsViewScale = new AnimatedFloat(() -> { });
public final AnimatedFloat fullScreenProgress = new AnimatedFloat(() -> { });
public final AnimatedFloat recentsViewScale = new AnimatedFloat();
public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
private final ScrollState mScrollState = new ScrollState();
private final int mPageSpacing;
@@ -40,14 +40,27 @@ public class TransformParams {
}
};
public static FloatProperty<TransformParams> TARGET_ALPHA =
new FloatProperty<TransformParams>("targetAlpha") {
@Override
public void setValue(TransformParams params, float v) {
params.setTargetAlpha(v);
}
@Override
public Float get(TransformParams params) {
return params.getTargetAlpha();
}
};
private float mProgress;
private float mTargetAlpha;
private float mCornerRadius;
private RemoteAnimationTargets mTargetSet;
private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
public TransformParams() {
mProgress = 0;
@@ -105,18 +118,20 @@ public class TransformParams {
}
/**
* Sets an alternate function which can be used to control the alpha of target app
* Sets an alternate function to control transform for non-target apps. The default
* implementation keeps the targets visible with alpha=1
*/
public TransformParams setTaskAlphaCallback(TargetAlphaProvider callback) {
mTaskAlphaCallback = callback;
public TransformParams setBaseBuilderProxy(BuilderProxy proxy) {
mBaseBuilderProxy = proxy;
return this;
}
/**
* Sets an alternate function which can be used to control the alpha of non-target app
* Sets an alternate function to control transform for home target. The default
* implementation keeps the targets visible with alpha=1
*/
public TransformParams setBaseAlphaCallback(TargetAlphaProvider callback) {
mBaseAlphaCallback = callback;
public TransformParams setHomeBuilderProxy(BuilderProxy proxy) {
mHomeBuilderProxy = proxy;
return this;
}
@@ -127,25 +142,24 @@ public class TransformParams {
RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
float progress = Utilities.boundToRange(getProgress(), 0, 1);
float alpha;
if (app.mode == targets.targetMode) {
alpha = mTaskAlphaCallback.getAlpha(app, getTargetAlpha());
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mHomeBuilderProxy.onBuildTargetParams(builder, app, this);
} else {
// Fade out Assistant overlay.
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
&& app.isNotInRecents) {
alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
float progress = Utilities.boundToRange(getProgress(), 0, 1);
builder.withAlpha(1 - Interpolators.DEACCEL_2_5.getInterpolation(progress));
} else {
builder.withAlpha(getTargetAlpha());
}
} else if (targets.hasRecents) {
// If home has a different target then recents, reverse anim the
// home target.
alpha = 1 - (progress * getTargetAlpha());
proxy.onBuildTargetParams(builder, app, this);
}
} else {
alpha = mBaseAlphaCallback.getAlpha(app, progress);
mBaseBuilderProxy.onBuildTargetParams(builder, app, this);
}
proxy.onBuildParams(builder.withAlpha(alpha), app, targets.targetMode, this);
surfaceParams[i] = builder.build();
}
return surfaceParams;
@@ -182,21 +196,13 @@ public class TransformParams {
}
}
public interface TargetAlphaProvider {
float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
}
@FunctionalInterface
public interface BuilderProxy {
default void onBuildParams(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, int targetMode, TransformParams params) {
if (app.mode == targetMode
&& app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
onBuildTargetParams(builder, app, params);
}
}
BuilderProxy NO_OP = (builder, app, params) -> { };
BuilderProxy ALWAYS_VISIBLE = (builder, app, params) ->builder.withAlpha(1);
default void onBuildTargetParams(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params) { }
void onBuildTargetParams(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params);
}
}
@@ -32,6 +32,7 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
@@ -647,6 +648,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
*/
@Override
public void registerRemoteAnimations() {
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
if (hasControlRemoteAppTransitionPermission()) {
mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */);
@@ -677,6 +681,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
*/
@Override
public void unregisterRemoteAnimations() {
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
if (hasControlRemoteAppTransitionPermission()) {
new ActivityCompat(mLauncher).unregisterRemoteAnimations();
@@ -38,11 +38,17 @@ public class AnimatedFloat {
}
};
private static final Runnable NO_OP = () -> { };
private final Runnable mUpdateCallback;
private ObjectAnimator mValueAnimator;
public float value;
public AnimatedFloat() {
this(NO_OP);
}
public AnimatedFloat(Runnable updateCallback) {
mUpdateCallback = updateCallback;
}
@@ -20,6 +20,7 @@ import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
import static com.android.systemui.shared.system.PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED;
@@ -138,6 +139,13 @@ public final class OverviewComponentObserver {
mActivityInterface.onAssistantVisibilityChanged(0.f);
}
if (SEPARATE_RECENTS_ACTIVITY.get()) {
mIsDefaultHome = false;
if (defaultHome == null) {
defaultHome = mMyHomeIntent.getComponent();
}
}
if (!mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) {
// User default home is same as out home app. Use Overview integrated in Launcher.
mActivityInterface = LauncherActivityInterface.INSTANCE;
@@ -1,5 +1,6 @@
package com.android.launcher3;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
import static com.android.launcher3.util.SystemUiController.UI_STATE_ROOT_VIEW;
@@ -177,7 +178,7 @@ public class LauncherRootView extends InsettableFrameLayout {
@TargetApi(Build.VERSION_CODES.Q)
public void setDisallowBackGesture(boolean disallowBackGesture) {
if (!Utilities.ATLEAST_Q) {
if (!Utilities.ATLEAST_Q || SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
mDisallowBackGesture = disallowBackGesture;
@@ -36,8 +36,6 @@ public final class FeatureFlags {
private static final List<DebugFlag> sDebugFlags = new ArrayList<>();
public static final String FLAGS_PREF_NAME = "featureFlags";
public static final String FLAG_ENABLE_FIXED_ROTATION_TRANSFORM =
"ENABLE_FIXED_ROTATION_TRANSFORM";
private FeatureFlags() { }
@@ -168,6 +166,10 @@ public final class FeatureFlags {
"ENABLE_ALL_APPS_EDU", true,
"Shows user a tutorial on how to get to All Apps after X amount of attempts.");
public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag(
"SEPARATE_RECENTS_ACTIVITY", false,
"Uses a separate recents activity instead of using the integrated recents+Launcher UI");
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {