Merge "Fix PipRotation tests"
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
new file mode 100644
index 0000000..687693c
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2022 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.server.job.controllers;
+
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.NonNull;
+import android.app.job.JobInfo;
+import android.content.Context;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.JobSchedulerBackgroundThread;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.utils.AlarmQueue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+
+/**
+ * Controller that tracks the number of flexible constraints being actively satisfied.
+ * Drops constraint for TOP apps and lowers number of required constraints with time.
+ *
+ * TODO: Plug in to other controllers (b/239047584), handle prefetch (b/238887951)
+ */
+public final class FlexibilityController extends StateController {
+    /**
+     * List of all potential flexible constraints
+     */
+    @VisibleForTesting
+    static final int FLEXIBLE_CONSTRAINTS = JobStatus.CONSTRAINT_BATTERY_NOT_LOW
+            | JobStatus.CONSTRAINT_CHARGING
+            | JobStatus.CONSTRAINT_CONNECTIVITY
+            | JobStatus.CONSTRAINT_IDLE;
+
+    /** Hard cutoff to remove flexible constraints */
+    private static final long DEADLINE_PROXIMITY_LIMIT_MS = 15 * MINUTE_IN_MILLIS;
+
+    /**
+     * Keeps track of what flexible constraints are satisfied at the moment.
+     * Is updated by the other controllers.
+     */
+    private int mSatisfiedFlexibleConstraints;
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    final FlexibilityTracker mFlexibilityTracker;
+
+    private final FlexibilityAlarmQueue mFlexibilityAlarmQueue;
+    private final long mMinTimeBetweenAlarmsMs = MINUTE_IN_MILLIS;
+
+    /**
+     * The percent of a Jobs lifecycle to drop number of required constraints.
+     * mPercentToDropConstraints[i] denotes that at x% of a Jobs lifecycle,
+     * the controller should have i+1 constraints dropped.
+     */
+    private final int[] mPercentToDropConstraints = {50, 60, 70, 80};
+
+    /** The default deadline that all flexible constraints should be dropped by. */
+    private final long mDefaultFlexibleDeadline = 72 * HOUR_IN_MILLIS;
+
+    public FlexibilityController(JobSchedulerService service) {
+        super(service);
+        mFlexibilityTracker = new FlexibilityTracker(FLEXIBLE_CONSTRAINTS);
+        mFlexibilityAlarmQueue = new FlexibilityAlarmQueue(
+                mContext, JobSchedulerBackgroundThread.get().getLooper());
+    }
+
+    /**
+     * StateController interface
+     */
+    @Override
+    public void maybeStartTrackingJobLocked(JobStatus js, JobStatus lastJob) {
+        if (js.hasFlexibilityConstraint()) {
+            mFlexibilityTracker.add(js);
+            js.setTrackingController(JobStatus.TRACKING_FLEXIBILITY);
+            final long nowElapsed = sElapsedRealtimeClock.millis();
+            js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
+            mFlexibilityAlarmQueue.addAlarm(js, getNextConstraintDropTimeElapsed(js));
+        }
+    }
+
+    @Override
+    public void maybeStopTrackingJobLocked(JobStatus js, JobStatus incomingJob, boolean forUpdate) {
+        if (js.clearTrackingController(JobStatus.TRACKING_FLEXIBILITY)) {
+            mFlexibilityAlarmQueue.removeAlarmForKey(js);
+            mFlexibilityTracker.remove(js);
+        }
+    }
+
+    /** Checks if the flexibility constraint is actively satisfied for a given job. */
+    @VisibleForTesting
+    boolean isFlexibilitySatisfiedLocked(JobStatus js) {
+        synchronized (mLock) {
+            return mService.getUidBias(js.getUid()) == JobInfo.BIAS_TOP_APP
+                    || mService.isCurrentlyRunningLocked(js)
+                    || getNumSatisfiedRequiredConstraintsLocked(js)
+                    >= js.getNumRequiredFlexibleConstraints();
+        }
+    }
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    int getNumSatisfiedRequiredConstraintsLocked(JobStatus js) {
+        return Integer.bitCount(js.getFlexibleConstraints() & mSatisfiedFlexibleConstraints);
+    }
+
+    /**
+     * Sets the controller's constraint to a given state.
+     * Changes flexibility constraint satisfaction for affected jobs.
+     */
+    @VisibleForTesting
+    void setConstraintSatisfied(int constraint, boolean state) {
+        synchronized (mLock) {
+            final boolean old = (mSatisfiedFlexibleConstraints & constraint) != 0;
+            if (old == state) {
+                return;
+            }
+
+            final int prevSatisfied = Integer.bitCount(mSatisfiedFlexibleConstraints);
+            mSatisfiedFlexibleConstraints =
+                    (mSatisfiedFlexibleConstraints & ~constraint) | (state ? constraint : 0);
+            final int curSatisfied = Integer.bitCount(mSatisfiedFlexibleConstraints);
+
+            // Only the max of the number of required flexible constraints will need to be updated
+            // The rest did not have a change in state and are still satisfied or unsatisfied.
+            final int numConstraintsToUpdate = Math.max(curSatisfied, prevSatisfied);
+
+            final ArraySet<JobStatus> jobs = mFlexibilityTracker.getJobsByNumRequiredConstraints(
+                    numConstraintsToUpdate);
+            final long nowElapsed = sElapsedRealtimeClock.millis();
+
+            for (int i = 0; i < jobs.size(); i++) {
+                JobStatus js = jobs.valueAt(i);
+                js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
+            }
+        }
+    }
+
+    /** Checks if the given constraint is satisfied in the flexibility controller. */
+    @VisibleForTesting
+    boolean isConstraintSatisfied(int constraint) {
+        return (mSatisfiedFlexibleConstraints & constraint) != 0;
+    }
+
+    /** The elapsed time that marks when the next constraint should be dropped. */
+    @VisibleForTesting
+    @ElapsedRealtimeLong
+    long getNextConstraintDropTimeElapsed(JobStatus js) {
+        final long earliest = js.getEarliestRunTime() == JobStatus.NO_EARLIEST_RUNTIME
+                ? js.enqueueTime : js.getEarliestRunTime();
+        final long latest = js.getLatestRunTimeElapsed() == JobStatus.NO_LATEST_RUNTIME
+                ? earliest + mDefaultFlexibleDeadline
+                : js.getLatestRunTimeElapsed();
+        final int percent = mPercentToDropConstraints[js.getNumDroppedFlexibleConstraints()];
+        final long percentInTime = ((latest - earliest) * percent) / 100;
+        return earliest + percentInTime;
+    }
+
+    @Override
+    @GuardedBy("mLock")
+    public void onUidBiasChangedLocked(int uid, int prevBias, int newBias) {
+        if (prevBias != JobInfo.BIAS_TOP_APP && newBias != JobInfo.BIAS_TOP_APP) {
+            return;
+        }
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        List<JobStatus> jobsByUid = mService.getJobStore().getJobsByUid(uid);
+        for (int i = 0; i < jobsByUid.size(); i++) {
+            JobStatus js = jobsByUid.get(i);
+            if (js.hasFlexibilityConstraint()) {
+                js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
+            }
+        }
+    }
+
+    @VisibleForTesting
+    class FlexibilityTracker {
+        final ArrayList<ArraySet<JobStatus>> mTrackedJobs;
+
+        FlexibilityTracker(int flexibleConstraints) {
+            mTrackedJobs = new ArrayList<>();
+            int numFlexibleConstraints = Integer.bitCount(flexibleConstraints);
+            for (int i = 0; i <= numFlexibleConstraints; i++) {
+                mTrackedJobs.add(new ArraySet<JobStatus>());
+            }
+        }
+
+        /** Gets every tracked job with a given number of required constraints. */
+        public ArraySet<JobStatus> getJobsByNumRequiredConstraints(int numRequired) {
+            return mTrackedJobs.get(numRequired - 1);
+        }
+
+        /** adds a JobStatus object based on number of required flexible constraints. */
+        public void add(JobStatus js) {
+            if (js.getNumRequiredFlexibleConstraints() <= 0) {
+                return;
+            }
+            mTrackedJobs.get(js.getNumRequiredFlexibleConstraints() - 1).add(js);
+        }
+
+        /** Removes a JobStatus object. */
+        public void remove(JobStatus js) {
+            if (js.getNumRequiredFlexibleConstraints() == 0) {
+                return;
+            }
+            mTrackedJobs.get(js.getNumRequiredFlexibleConstraints() - 1).remove(js);
+        }
+
+        /** Returns all tracked jobs. */
+        public ArrayList<ArraySet<JobStatus>> getArrayList() {
+            return mTrackedJobs;
+        }
+
+        /**
+         * Adjusts number of required flexible constraints and sorts it into the tracker.
+         * Returns false if the job status's number of flexible constraints is now 0.
+         * Jobs with 0 required flexible constraints are removed from the tracker.
+         */
+        public boolean adjustJobsRequiredConstraints(JobStatus js, int n) {
+            remove(js);
+            js.adjustNumRequiredFlexibleConstraints(n);
+            final long nowElapsed = sElapsedRealtimeClock.millis();
+            js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
+            if (js.getNumRequiredFlexibleConstraints() <= 0) {
+                maybeStopTrackingJobLocked(js, null, false);
+                return false;
+            }
+            add(js);
+            return true;
+        }
+
+        public void dump(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
+            for (int i = 0; i < mTrackedJobs.size(); i++) {
+                ArraySet<JobStatus> jobs = mTrackedJobs.get(i);
+                for (int j = 0; j < mTrackedJobs.size(); j++) {
+                    final JobStatus js = jobs.valueAt(j);
+                    if (!predicate.test(js)) {
+                        continue;
+                    }
+                    pw.print("#");
+                    js.printUniqueId(pw);
+                    pw.print(" from ");
+                    UserHandle.formatUid(pw, js.getSourceUid());
+                    pw.println();
+                }
+            }
+        }
+    }
+
+    private class FlexibilityAlarmQueue extends AlarmQueue<JobStatus> {
+        private FlexibilityAlarmQueue(Context context, Looper looper) {
+            super(context, looper, "*job.flexibility_check*",
+                    "Flexible Constraint Check", false, mMinTimeBetweenAlarmsMs);
+        }
+
+        @Override
+        protected boolean isForUser(@NonNull JobStatus js, int userId) {
+            return js.getSourceUserId() == userId;
+        }
+
+        @Override
+        protected void processExpiredAlarms(@NonNull ArraySet<JobStatus> expired) {
+            synchronized (mLock) {
+                JobStatus js;
+                for (int i = 0; i < expired.size(); i++) {
+                    js = expired.valueAt(i);
+                    long time = getNextConstraintDropTimeElapsed(js);
+                    if (js.getLatestRunTimeElapsed() - time < DEADLINE_PROXIMITY_LIMIT_MS) {
+                        mFlexibilityTracker.adjustJobsRequiredConstraints(js,
+                                -js.getNumRequiredFlexibleConstraints());
+                        continue;
+                    }
+                    if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1)) {
+                        mFlexibilityAlarmQueue.addAlarm(js, time);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    @GuardedBy("mLock")
+    public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
+        pw.println("# Constraints Satisfied: " + Integer.bitCount(mSatisfiedFlexibleConstraints));
+        pw.println();
+
+        mFlexibilityTracker.dump(pw, predicate);
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index e0f58e3..41cf4212 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -16,6 +16,9 @@
 
 package com.android.server.job.controllers;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+
 import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
 import static com.android.server.job.JobSchedulerService.EXEMPTED_INDEX;
 import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
@@ -99,6 +102,7 @@
     static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;      // Implicit constraint
     static final int CONSTRAINT_PREFETCH = 1 << 23;
     static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint
+    static final int CONSTRAINT_FLEXIBLE = 1 << 21; // Implicit constraint
 
     // The following set of dynamic constraints are for specific use cases (as explained in their
     // relative naming and comments). Right now, they apply different constraints, which is fine,
@@ -118,6 +122,22 @@
                     | CONSTRAINT_IDLE;
 
     /**
+     * The set of constraints that are required to satisfy flexible constraints.
+     * Constraints explicitly requested by the job will not be added to the set.
+     */
+    private int mFlexibleConstraints;
+
+    /**
+     * Keeps track of how many flexible constraints must be satisfied for the job to execute.
+     */
+    private int mNumRequiredFlexibleConstraints;
+
+    /**
+     * Number of required flexible constraints that have been dropped.
+     */
+    private int mNumDroppedFlexibleConstraints;
+
+    /**
      * The additional set of dynamic constraints that must be met if this is an expedited job that
      * had a long enough run while the device was Dozing or in battery saver.
      */
@@ -305,6 +325,12 @@
     public static final int TRACKING_QUOTA = 1 << 6;
 
     /**
+     * Flag for {@link #trackingControllers}: the flexibility controller is currently tracking this
+     * job.
+     */
+    public static final int TRACKING_FLEXIBILITY = 1 << 7;
+
+    /**
      * Bit mask of controllers that are currently tracking the job.
      */
     private int trackingControllers;
@@ -318,6 +344,8 @@
      */
     public static final int INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION = 1 << 0;
 
+    /** Minimum difference between start and end time to have flexible constraint */
+    private static final long MIN_WINDOW_FOR_FLEXIBILITY_MS = HOUR_IN_MILLIS;
     /**
      * Versatile, persistable flags for a job that's updated within the system server,
      * as opposed to {@link JobInfo#flags} that's set by callers.
@@ -525,6 +553,33 @@
             }
         }
         mHasExemptedMediaUrisOnly = exemptedMediaUrisOnly;
+
+        if (isRequestedExpeditedJob()
+                || ((latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis)
+                < MIN_WINDOW_FOR_FLEXIBILITY_MS)
+                || job.isPrefetch()) {
+            mFlexibleConstraints = 0;
+        } else {
+            if ((requiredConstraints & CONSTRAINT_CHARGING) == 0) {
+                mFlexibleConstraints |= CONSTRAINT_CHARGING;
+            }
+            if ((requiredConstraints & CONSTRAINT_BATTERY_NOT_LOW) == 0) {
+                mFlexibleConstraints |= CONSTRAINT_BATTERY_NOT_LOW;
+            }
+            if ((requiredConstraints & CONSTRAINT_IDLE) == 0) {
+                mFlexibleConstraints |= CONSTRAINT_IDLE;
+            }
+            if (job.getRequiredNetwork() != null
+                    && !job.getRequiredNetwork().hasCapability(NET_CAPABILITY_NOT_METERED)) {
+                mFlexibleConstraints |= CONSTRAINT_CONNECTIVITY;
+            }
+        }
+        if (mFlexibleConstraints != 0) {
+            // TODO(b/239047584): Uncomment once Flexibility Controller is plugged in.
+            // requiredConstraints |= CONSTRAINT_FLEXIBLE;
+            mNumRequiredFlexibleConstraints = Integer.bitCount(mFlexibleConstraints);
+        }
+
         this.requiredConstraints = requiredConstraints;
         mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
         addDynamicConstraints(dynamicConstraints);
@@ -1082,12 +1137,35 @@
         return hasConstraint(CONSTRAINT_IDLE);
     }
 
+    /** Returns true if the job has a prefetch constraint */
+    public boolean hasPrefetchConstraint() {
+        return hasConstraint(CONSTRAINT_PREFETCH);
+    }
+
     public boolean hasContentTriggerConstraint() {
         // No need to check mDynamicConstraints since content trigger will only be in that list if
         // it's already in the requiredConstraints list.
         return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
     }
 
+    /** Returns true if the job has flexible job constraints enabled */
+    public boolean hasFlexibilityConstraint() {
+        return (requiredConstraints & CONSTRAINT_FLEXIBLE) != 0;
+    }
+
+    /** Returns the number of flexible job constraints required to be satisfied to execute */
+    public int getNumRequiredFlexibleConstraints() {
+        return mNumRequiredFlexibleConstraints;
+    }
+
+    /**
+     * Returns the number of required flexible job constraints that have been dropped with time.
+     * The lower this number is the easier it is for the flexibility constraint to be satisfied.
+     */
+    public int getNumDroppedFlexibleConstraints() {
+        return mNumDroppedFlexibleConstraints;
+    }
+
     /**
      * Checks both {@link #requiredConstraints} and {@link #mDynamicConstraints} to see if this job
      * requires the specified constraint.
@@ -1128,6 +1206,10 @@
         return mOriginalLatestRunTimeElapsedMillis;
     }
 
+    public int getFlexibleConstraints() {
+        return mFlexibleConstraints;
+    }
+
     public void setOriginalLatestRunTimeElapsed(long latestRunTimeElapsed) {
         mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsed;
     }
@@ -1301,6 +1383,11 @@
         return false;
     }
 
+    /** @return true if the constraint was changed, false otherwise. */
+    boolean setFlexibilityConstraintSatisfied(final long nowElapsed, boolean state) {
+        return setConstraintSatisfied(CONSTRAINT_FLEXIBLE, nowElapsed, state);
+    }
+
     /**
      * Sets whether or not this job is approved to be treated as an expedited job based on quota
      * policy.
@@ -1490,6 +1577,18 @@
         trackingControllers |= which;
     }
 
+    /** Adjusts the number of required flexible constraints by the given number */
+    public void adjustNumRequiredFlexibleConstraints(int adjustment) {
+        mNumRequiredFlexibleConstraints += adjustment;
+        if (mNumRequiredFlexibleConstraints < 0) {
+            mNumRequiredFlexibleConstraints = 0;
+        }
+        mNumDroppedFlexibleConstraints -= adjustment;
+        if (mNumDroppedFlexibleConstraints < 0) {
+            mNumDroppedFlexibleConstraints = 0;
+        }
+    }
+
     /**
      * Add additional constraints to prevent this job from running when doze or battery saver are
      * active.
@@ -1650,12 +1749,14 @@
     /** All constraints besides implicit and deadline. */
     static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
             | CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | CONSTRAINT_CONNECTIVITY
-            | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER | CONSTRAINT_PREFETCH;
+            | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER | CONSTRAINT_PREFETCH
+            | CONSTRAINT_FLEXIBLE;
 
     // Soft override covers all non-"functional" constraints
     static final int SOFT_OVERRIDE_CONSTRAINTS =
             CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
-                    | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE | CONSTRAINT_PREFETCH;
+                    | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE | CONSTRAINT_PREFETCH
+                    | CONSTRAINT_FLEXIBLE;
 
     /** Returns true whenever all dynamically set constraints are satisfied. */
     public boolean areDynamicConstraintsSatisfied() {
diff --git a/core/java/android/app/timedetector/TimeDetectorHelper.java b/core/java/android/app/timedetector/TimeDetectorHelper.java
new file mode 100644
index 0000000..8752ee0
--- /dev/null
+++ b/core/java/android/app/timedetector/TimeDetectorHelper.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 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 android.app.timedetector;
+
+import android.annotation.NonNull;
+import android.os.Build;
+
+import java.time.Instant;
+
+/**
+ * A utility class for fundamental time detector-related logic that doesn't need to communicate with
+ * the time detector service, i.e. because it can use SDK APIs or hard-coded facts, and doesn't need
+ * permissions or singleton state. Putting logic here avoids the need to expose binder-based calls
+ * or to duplicate code to share related logic (since android.app.timedetector classes are visible
+ * to all processes).
+ *
+ * @hide
+ */
+// Not final for easy replacement / mocking during tests.
+public class TimeDetectorHelper {
+
+    /**
+     * See {@link #getManualDateSelectionYearMin()}. Chosen to produce Unix epoch times be greater
+     * than {@link #MANUAL_SUGGESTION_LOWER_BOUND}.
+     */
+    private static final int MANUAL_SUGGESTION_YEAR_MIN = 2008;
+
+    /**
+     * The maximum gregorian calendar year to allow for manual date selection on devices unlikely to
+     * have Y2038 issues. This serves as a sensible UI-enforced limit though the system server may
+     * support a larger upper bound. Users besides future archeologists are unlikely to need higher
+     * values, for a few years at least.
+     */
+    private static final int MANUAL_SUGGESTION_YEAR_MAX_WITHOUT_Y2038_ISSUE = 2100;
+
+    /**
+     * The maximum gregorian calendar year to allow for manual date selection on devices that may
+     * have Y2038 issues. This serves as a sensible UI-enforced limit though the system server may
+     * support a larger upper bound. That is, the signed 32-bit milliseconds value is
+     * 03:14:07 UTC on 19 January 2038, but this constant means users can only enter dates up to
+     * 2037-12-31. See {@link #MANUAL_SUGGESTION_YEAR_MAX_WITH_Y2038_ISSUE}.
+     *
+     * <p>Note: This UI limit also doesn't prevent devices reaching the Y2038 roll-over time through
+     * the natural passage of time, it just prevents users potentially causing issues in the years
+     * leading up to it accidentally via the UI.
+     */
+    private static final int MANUAL_SUGGESTION_YEAR_MAX_WITH_Y2038_ISSUE = 2037;
+
+    /**
+     * The upper bound for valid suggestions when the Y2038 issue is a risk. This is the instant
+     * when the Y2038 issue occurs.
+     */
+    private static final Instant SUGGESTION_UPPER_BOUND_WITH_Y2038_ISSUE =
+            Instant.ofEpochMilli(1000L * Integer.MAX_VALUE);
+
+    /**
+     * The upper bound for valid suggestions when the Y2038 issue is not a risk. This values means
+     * there is no practical upper bound.
+     *
+     * <p>Make sure this value remains in the value representable as a signed int64 Unix epoch
+     * millis value as in various places {@link Instant#toEpochMilli()} is called, and that throws
+     * an exception if the value is too large.
+     */
+    private static final Instant SUGGESTION_UPPER_BOUND_WIITHOUT_Y2038_ISSUE =
+            Instant.ofEpochMilli(Long.MAX_VALUE);
+
+    /** See {@link #getManualSuggestionLowerBound()}. */
+    private static final Instant MANUAL_SUGGESTION_LOWER_BOUND =
+            Instant.ofEpochMilli(1194220800000L); // Nov 5, 2007, 0:00 UTC
+
+    /**
+     * The lowest value in Unix epoch milliseconds that is considered a valid automatic suggestion.
+     * See also {@link #MANUAL_SUGGESTION_LOWER_BOUND}.
+     *
+     * <p>Note that this is a default value. The lower value enforced can be overridden to be
+     * lower in the system server with flags for testing.
+     */
+    private static final Instant AUTO_SUGGESTION_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli(
+            Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));
+
+    /** The singleton instance of this class. */
+    public static final TimeDetectorHelper INSTANCE = new TimeDetectorHelper();
+
+    /** Constructor present for subclassing in tests. Use {@link #INSTANCE} in production code. */
+    protected TimeDetectorHelper() {}
+
+    /**
+     * Returns the minimum gregorian calendar year to offer for manual date selection. This serves
+     * as a sensible UI-enforced lower limit, the system server may support a smaller lower bound.
+     */
+    public int getManualDateSelectionYearMin() {
+        return MANUAL_SUGGESTION_YEAR_MIN;
+    }
+
+    /**
+     * Returns the maximum gregorian calendar year to offer for manual date selection. This serves
+     * as a sensible UI-enforced lower limit, the system server may support a larger upper bound.
+     */
+    public int getManualDateSelectionYearMax() {
+        return getDeviceHasY2038Issue()
+                ? MANUAL_SUGGESTION_YEAR_MAX_WITH_Y2038_ISSUE
+                : MANUAL_SUGGESTION_YEAR_MAX_WITHOUT_Y2038_ISSUE;
+    }
+
+    /**
+     * Returns the lowest value in Unix epoch milliseconds that is considered a valid manual
+     * suggestion. For historical reasons Android has a different lower limit for manual input than
+     * automatic. This may change in the future to align with automatic suggestions, but has been
+     * kept initially to avoid breaking manual tests that are hard-coded with old dates real users
+     * will never want to use.
+     */
+    @NonNull
+    public Instant getManualSuggestionLowerBound() {
+        return MANUAL_SUGGESTION_LOWER_BOUND;
+    }
+
+    /**
+     * Returns the lowest value in Unix epoch milliseconds that is considered a valid automatic
+     * suggestion. See also {@link #MANUAL_SUGGESTION_LOWER_BOUND}.
+     *
+     * <p>Note that this is a default value. The lower value enforced can be overridden to be
+     * different in the system server with server flags.
+     */
+    @NonNull
+    public Instant getAutoSuggestionLowerBoundDefault() {
+        return AUTO_SUGGESTION_LOWER_BOUND_DEFAULT;
+    }
+
+    /** Returns the upper bound to enforce for all time suggestions (manual and automatic). */
+    @NonNull
+    public Instant getSuggestionUpperBound() {
+        return getDeviceHasY2038Issue()
+                ? SUGGESTION_UPPER_BOUND_WITH_Y2038_ISSUE
+                : SUGGESTION_UPPER_BOUND_WIITHOUT_Y2038_ISSUE;
+    }
+
+    /**
+     * Returns {@code true} if the device may be at risk of time_t overflow (because bionic
+     * defines time_t as a 32-bit signed integer for 32-bit processes).
+     */
+    private boolean getDeviceHasY2038Issue() {
+        return Build.SUPPORTED_32_BIT_ABIS.length > 0;
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index c672476..24f02ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -681,9 +681,12 @@
             return;
         }
 
+        if (mState.getState() == STATE_ACTIVE) {
+            mOneHandedUiEventLogger.writeEvent(
+                    OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
+        }
+
         mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
-        mOneHandedUiEventLogger.writeEvent(
-                OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
     }
 
     /**
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 071667a..c84f5b0 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -172,7 +172,7 @@
             try {
                 mMediaRouterService.startScan(client);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -196,7 +196,7 @@
             try {
                 mMediaRouterService.stopScan(client);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -361,9 +361,8 @@
             return mMediaRouterService.getSystemSessionInfoForPackage(
                     getOrCreateClient(), packageName);
         } catch (RemoteException ex) {
-            Log.e(TAG, "Unable to get current system session info", ex);
+            throw ex.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -429,7 +428,7 @@
             try {
                 return mMediaRouterService.getRemoteSessions(client);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
         return Collections.emptyList();
@@ -521,7 +520,7 @@
                 int requestId = mNextRequestId.getAndIncrement();
                 mMediaRouterService.setRouteVolumeWithManager(client, requestId, route, volume);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to set route volume.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -551,7 +550,7 @@
                 mMediaRouterService.setSessionVolumeWithManager(
                         client, requestId, sessionInfo.getId(), volume);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to set session volume.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -816,7 +815,7 @@
                 mMediaRouterService.selectRouteWithManager(
                         client, requestId, sessionInfo.getId(), route);
             } catch (RemoteException ex) {
-                Log.e(TAG, "selectRoute: Failed to send a request.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -858,7 +857,7 @@
                 mMediaRouterService.deselectRouteWithManager(
                         client, requestId, sessionInfo.getId(), route);
             } catch (RemoteException ex) {
-                Log.e(TAG, "deselectRoute: Failed to send a request.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -883,7 +882,7 @@
                 mMediaRouterService.releaseSessionWithManager(
                         client, requestId, sessionInfo.getId());
             } catch (RemoteException ex) {
-                Log.e(TAG, "releaseSession: Failed to send a request", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -903,7 +902,7 @@
                 mMediaRouterService.transferToRouteWithManager(
                         client, requestId, session.getId(), route);
             } catch (RemoteException ex) {
-                Log.e(TAG, "transferToRoute: Failed to send a request.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -923,7 +922,7 @@
                 mMediaRouterService.requestCreateSessionWithManager(
                         client, requestId, oldSession, route);
             } catch (RemoteException ex) {
-                Log.e(TAG, "requestCreateSession: Failed to send a request", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -979,10 +978,9 @@
                 mClient = client;
                 return client;
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to register media router manager.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
-        return null;
     }
 
     /**
diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
index 50f69d1..c629d96 100644
--- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
+++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
@@ -71,6 +71,8 @@
         <TextView
             android:id="@+id/entity_header_second_summary"
             style="@style/TextAppearance.EntityHeaderSummary"
+            android:singleLine="false"
+            android:maxLines="4"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"/>
 
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index dbdbdf6..2f36ab9 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -515,11 +515,20 @@
         dialogContentWithBackground.setTransitionVisibility(View.INVISIBLE)
 
         // Make sure the dialog is visible instantly and does not do any window animation.
-        window.attributes.windowAnimations = R.style.Animation_LaunchAnimation
+        val attributes = window.attributes
+        attributes.windowAnimations = R.style.Animation_LaunchAnimation
 
         // Ensure that the animation is not clipped by the display cut-out when animating this
         // dialog into an app.
-        window.attributes.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+        attributes.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+
+        // Ensure that the animation is not clipped by the navigation/task bars when animating this
+        // dialog into an app.
+        val wasFittingNavigationBars =
+            attributes.fitInsetsTypes and WindowInsets.Type.navigationBars() != 0
+        attributes.fitInsetsTypes =
+            attributes.fitInsetsTypes and WindowInsets.Type.navigationBars().inv()
+
         window.attributes = window.attributes
 
         // We apply the insets ourselves to make sure that the paddings are set on the correct
@@ -527,7 +536,13 @@
         window.setDecorFitsSystemWindows(false)
         val viewWithInsets = (dialogContentWithBackground.parent as ViewGroup)
         viewWithInsets.setOnApplyWindowInsetsListener { view, windowInsets ->
-            val insets = windowInsets.getInsets(WindowInsets.Type.displayCutout())
+            val type = if (wasFittingNavigationBars) {
+                WindowInsets.Type.displayCutout() or WindowInsets.Type.navigationBars()
+            } else {
+                WindowInsets.Type.displayCutout()
+            }
+
+            val insets = windowInsets.getInsets(type)
             view.setPadding(insets.left, insets.top, insets.right, insets.bottom)
             WindowInsets.CONSUMED
         }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 15c1761..a553e19 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -145,6 +145,9 @@
     public static final ResourceBooleanFlag STATUS_BAR_USER_SWITCHER =
             new ResourceBooleanFlag(602, R.bool.flag_user_switcher_chip);
 
+    public static final BooleanFlag STATUS_BAR_LETTERBOX_APPEARANCE =
+            new BooleanFlag(603, false);
+
     /***************************************/
     // 700 - dialer/calls
     public static final BooleanFlag ONGOING_CALL_STATUS_BAR_CHIP =
diff --git a/services/contentcapture/Android.bp b/services/contentcapture/Android.bp
index 434f239..5392c2c 100644
--- a/services/contentcapture/Android.bp
+++ b/services/contentcapture/Android.bp
@@ -17,6 +17,9 @@
 java_library_static {
     name: "services.contentcapture",
     defaults: ["platform_service_defaults"],
-    srcs: [":services.contentcapture-sources"],
+    srcs: [
+        ":services.contentcapture-sources",
+        "java/**/*.logtags",
+    ],
     libs: ["services.core"],
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 7a95a8f..1ca68d7 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -60,6 +60,7 @@
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -88,6 +89,11 @@
 
     private static final String TAG = ContentCapturePerUserService.class.getSimpleName();
 
+    private static final int EVENT_LOG_CONNECT_STATE_DIED = 0;
+    static final int EVENT_LOG_CONNECT_STATE_CONNECTED = 1;
+    static final int EVENT_LOG_CONNECT_STATE_DISCONNECTED = 2;
+
+
     @GuardedBy("mLock")
     private final SparseArray<ContentCaptureServerSession> mSessions = new SparseArray<>();
 
@@ -190,9 +196,13 @@
         Slog.w(TAG, "remote service died: " + service);
         synchronized (mLock) {
             mZombie = true;
+            ComponentName serviceComponent = getServiceComponentName();
             writeServiceEvent(
                     FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_REMOTE_SERVICE_DIED,
-                    getServiceComponentName());
+                    serviceComponent);
+            EventLog.writeEvent(EventLogTags.CC_CONNECT_STATE_CHANGED, mUserId,
+                    serviceComponent != null ? serviceComponent.flattenToShortString() : "",
+                    EVENT_LOG_CONNECT_STATE_DIED);
         }
     }
 
@@ -614,11 +624,16 @@
                         ? "null_activities" : activities.size() + " activities") + ")"
                         + " for user " + mUserId);
             }
+            int packageCount = packages != null ? packages.size() : 0;
+            int activityCount = activities != null ? activities.size() : 0;
 
             ArraySet<String> oldList =
                     mMaster.mGlobalContentCaptureOptions.getWhitelistedPackages(mUserId);
+            EventLog.writeEvent(EventLogTags.CC_CURRENT_ALLOWLIST, mUserId, oldList.size());
 
             mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
+            EventLog.writeEvent(EventLogTags.CC_SET_ALLOWLIST, mUserId,
+                    packageCount, activityCount);
             writeSetWhitelistEvent(getServiceComponentName(), packages, activities);
 
             updateContentCaptureOptions(oldList);
@@ -699,12 +714,14 @@
         private void updateContentCaptureOptions(@Nullable ArraySet<String> oldList) {
             ArraySet<String> adding = mMaster.mGlobalContentCaptureOptions
                     .getWhitelistedPackages(mUserId);
+            EventLog.writeEvent(EventLogTags.CC_CURRENT_ALLOWLIST, mUserId, adding.size());
 
             if (oldList != null && adding != null) {
                 adding.removeAll(oldList);
             }
 
             int N = adding != null ? adding.size() : 0;
+            EventLog.writeEvent(EventLogTags.CC_UPDATE_OPTIONS, mUserId, N);
             for (int i = 0; i < N; i++) {
                 String packageName = adding.valueAt(i);
                 ContentCaptureOptions options = mMaster.mGlobalContentCaptureOptions
diff --git a/services/contentcapture/java/com/android/server/contentcapture/EventLogTags.logtags b/services/contentcapture/java/com/android/server/contentcapture/EventLogTags.logtags
new file mode 100644
index 0000000..6722b9e
--- /dev/null
+++ b/services/contentcapture/java/com/android/server/contentcapture/EventLogTags.logtags
@@ -0,0 +1,8 @@
+# See system/logging/logcat/event.logtags for a description of the format of this file.
+
+option java_package com.android.server.contentcapture
+
+53200 cc_connect_state_changed (User|1|5),(component|3),(type|1)
+53201 cc_set_allowlist (User|1|5),(package_count|1),(activity_count|1)
+53202 cc_current_allowlist (User|1|5),(count|1)
+53203 cc_update_options (User|1|5),(count|1)
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 1efe55a..e22a9d0 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -31,6 +31,7 @@
 import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.IDataShareCallback;
 import android.service.contentcapture.SnapshotData;
+import android.util.EventLog;
 import android.util.Slog;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.DataRemovalRequest;
@@ -47,6 +48,7 @@
     private final IBinder mServerCallback;
     private final int mIdleUnbindTimeoutMs;
     private final ContentCapturePerUserService mPerUserService;
+    private final int mUserId;
 
     RemoteContentCaptureService(Context context, String serviceInterface,
             ComponentName serviceComponentName, IContentCaptureServiceCallback callback, int userId,
@@ -61,6 +63,7 @@
         mPerUserService = perUserService;
         mServerCallback = callback.asBinder();
         mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
+        mUserId = userId;
 
         // Bind right away, which will trigger a onConnected() on service's
         ensureBoundLocked();
@@ -88,6 +91,9 @@
                     writeServiceEvent(
                             FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_CONNECTED,
                             mComponentName);
+                    EventLog.writeEvent(EventLogTags.CC_CONNECT_STATE_CHANGED, mUserId,
+                            mComponentName != null ? mComponentName.flattenToShortString() : "",
+                            ContentCapturePerUserService.EVENT_LOG_CONNECT_STATE_CONNECTED);
                 } finally {
                     // Update the system-service state, in case the service reconnected after
                     // dying
@@ -98,6 +104,9 @@
                 writeServiceEvent(
                         FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_DISCONNECTED,
                         mComponentName);
+                EventLog.writeEvent(EventLogTags.CC_CONNECT_STATE_CHANGED, mUserId,
+                        mComponentName != null ? mComponentName.flattenToShortString() : "",
+                        ContentCapturePerUserService.EVENT_LOG_CONNECT_STATE_DISCONNECTED);
             }
         } catch (Exception e) {
             Slog.w(mTag, "Exception calling onConnectedStateChanged(" + connected + "): " + e);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 46b0ded..556fa14 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -10377,6 +10377,11 @@
 
         @Override
         public void setAccessibilityServiceUids(IntArray uids) {
+            // TODO(b/233287010): Fix voice interaction and a11y concurrency in audio policy service
+            if (isPlatformAutomotive()) {
+                return;
+            }
+
             synchronized (mAccessibilityServiceUidsLock) {
                 if (uids.size() == 0) {
                     mAccessibilityServiceUids = null;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8d0114d..794c06f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1,16 +1,17 @@
 /*
+ * Copyright (C) 2022 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
+ * 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
+ *      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.
+ * 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.server.inputmethod;
@@ -367,29 +368,29 @@
     Future<?> mImeDrawsImeNavBarResLazyInitFuture;
 
     static class SessionState {
-        final ClientState client;
-        final IInputMethodInvoker method;
+        final ClientState mClient;
+        final IInputMethodInvoker mMethod;
 
-        IInputMethodSession session;
-        InputChannel channel;
+        IInputMethodSession mSession;
+        InputChannel mChannel;
 
         @Override
         public String toString() {
-            return "SessionState{uid " + client.uid + " pid " + client.pid
+            return "SessionState{uid " + mClient.mUid + " pid " + mClient.mPid
                     + " method " + Integer.toHexString(
-                            IInputMethodInvoker.getBinderIdentityHashCode(method))
+                    IInputMethodInvoker.getBinderIdentityHashCode(mMethod))
                     + " session " + Integer.toHexString(
-                            System.identityHashCode(session))
-                    + " channel " + channel
+                    System.identityHashCode(mSession))
+                    + " channel " + mChannel
                     + "}";
         }
 
-        SessionState(ClientState _client, IInputMethodInvoker _method,
-                IInputMethodSession _session, InputChannel _channel) {
-            client = _client;
-            method = _method;
-            session = _session;
-            channel = _channel;
+        SessionState(ClientState client, IInputMethodInvoker method,
+                IInputMethodSession session, InputChannel channel) {
+            mClient = client;
+            mMethod = method;
+            mSession = session;
+            mChannel = channel;
         }
     }
 
@@ -405,7 +406,7 @@
 
         @Override
         public String toString() {
-            return "AccessibilitySessionState{uid " + mClient.uid + " pid " + mClient.pid
+            return "AccessibilitySessionState{uid " + mClient.mUid + " pid " + mClient.mPid
                     + " id " + Integer.toHexString(mId)
                     + " session " + Integer.toHexString(
                     System.identityHashCode(mSession))
@@ -436,37 +437,37 @@
     }
 
     static final class ClientState {
-        final IInputMethodClientInvoker client;
-        final IRemoteInputConnection fallbackInputConnection;
-        final int uid;
-        final int pid;
-        final int selfReportedDisplayId;
-        final InputBinding binding;
-        final ClientDeathRecipient clientDeathRecipient;
+        final IInputMethodClientInvoker mClient;
+        final IRemoteInputConnection mFallbackInputConnection;
+        final int mUid;
+        final int mPid;
+        final int mSelfReportedDisplayId;
+        final InputBinding mBinding;
+        final ClientDeathRecipient mClientDeathRecipient;
 
-        boolean sessionRequested;
+        boolean mSessionRequested;
         boolean mSessionRequestedForAccessibility;
-        SessionState curSession;
+        SessionState mCurSession;
         SparseArray<AccessibilitySessionState> mAccessibilitySessions = new SparseArray<>();
 
         @Override
         public String toString() {
             return "ClientState{" + Integer.toHexString(
-                    System.identityHashCode(this)) + " uid=" + uid
-                    + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
+                    System.identityHashCode(this)) + " mUid=" + mUid
+                    + " mPid=" + mPid + " mSelfReportedDisplayId=" + mSelfReportedDisplayId + "}";
         }
 
-        ClientState(IInputMethodClientInvoker _client,
-                IRemoteInputConnection _fallbackInputConnection,
-                int _uid, int _pid, int _selfReportedDisplayId,
-                ClientDeathRecipient _clientDeathRecipient) {
-            client = _client;
-            fallbackInputConnection = _fallbackInputConnection;
-            uid = _uid;
-            pid = _pid;
-            selfReportedDisplayId = _selfReportedDisplayId;
-            binding = new InputBinding(null, fallbackInputConnection.asBinder(), uid, pid);
-            clientDeathRecipient = _clientDeathRecipient;
+        ClientState(IInputMethodClientInvoker client,
+                IRemoteInputConnection fallbackInputConnection,
+                int uid, int pid, int selfReportedDisplayId,
+                ClientDeathRecipient clientDeathRecipient) {
+            mClient = client;
+            mFallbackInputConnection = fallbackInputConnection;
+            mUid = uid;
+            mPid = pid;
+            mSelfReportedDisplayId = selfReportedDisplayId;
+            mBinding = new InputBinding(null, mFallbackInputConnection.asBinder(), mUid, mPid);
+            mClientDeathRecipient = clientDeathRecipient;
         }
     }
 
@@ -764,7 +765,7 @@
      */
     boolean mBoundToAccessibility;
 
-     /**
+    /**
      * Currently enabled session.
      */
     @GuardedBy("ImfLock.class")
@@ -1009,7 +1010,7 @@
          * <p>TODO: Consider to follow what other system services have been doing to manage
          * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
          */
-        private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 32;
+        private static final int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 32;
 
         /**
          * Entry size for non low-RAM devices.
@@ -1017,7 +1018,7 @@
          * <p>TODO: Consider to follow what other system services have been doing to manage
          * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
          */
-        private final static int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
+        private static final int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
 
         private static int getEntrySize() {
             if (ActivityManager.isLowRamDeviceStatic()) {
@@ -1140,7 +1141,7 @@
 
                 pw.print(prefix);
                 pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
-                                entry.mTargetWindowSoftInputMode));
+                        entry.mTargetWindowSoftInputMode));
 
                 pw.print(prefix);
                 pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
@@ -1336,7 +1337,7 @@
          * rescanning.</p>
          */
         @GuardedBy("ImfLock.class")
-        final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
+        private final ArraySet<String> mKnownImePackageNames = new ArraySet<>();
 
         /**
          * Packages that are appeared, disappeared, or modified for whatever reason.
@@ -1364,7 +1365,7 @@
         }
 
         @GuardedBy("ImfLock.class")
-        final void addKnownImePackageNameLocked(@NonNull String packageName) {
+        void addKnownImePackageNameLocked(@NonNull String packageName) {
             mKnownImePackageNames.add(packageName);
         }
 
@@ -1387,9 +1388,9 @@
                     return false;
                 }
                 String curInputMethodId = mSettings.getSelectedInputMethod();
-                final int N = mMethodList.size();
+                final int numImes = mMethodList.size();
                 if (curInputMethodId != null) {
-                    for (int i=0; i<N; i++) {
+                    for (int i = 0; i < numImes; i++) {
                         InputMethodInfo imi = mMethodList.get(i);
                         if (imi.getId().equals(curInputMethodId)) {
                             for (String pkg : packages) {
@@ -1491,8 +1492,8 @@
             // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
             // TODO: Consider to create a utility method to do the following test. List.retainAll()
             // is an option, but it may still do some extra operations that we do not need here.
-            final int N = mChangedPackages.size();
-            for (int i = 0; i < N; ++i) {
+            final int numPackages = mChangedPackages.size();
+            for (int i = 0; i < numPackages; ++i) {
                 final String packageName = mChangedPackages.get(i);
                 if (mKnownImePackageNames.contains(packageName)) {
                     return true;
@@ -1512,9 +1513,9 @@
 
                 InputMethodInfo curIm = null;
                 String curInputMethodId = mSettings.getSelectedInputMethod();
-                final int N = mMethodList.size();
+                final int numImes = mMethodList.size();
                 if (curInputMethodId != null) {
-                    for (int i=0; i<N; i++) {
+                    for (int i = 0; i < numImes; i++) {
                         InputMethodInfo imi = mMethodList.get(i);
                         final String imiId = imi.getId();
                         if (imiId.equals(curInputMethodId)) {
@@ -1620,6 +1621,10 @@
     @GuardedBy("ImfLock.class")
     private UserSwitchHandlerTask mUserSwitchHandlerTask;
 
+    /**
+     * {@link SystemService} used to publish and manage the lifecycle of
+     * {@link InputMethodManagerService}.
+     */
     public static final class Lifecycle extends SystemService {
         private final InputMethodManagerService mService;
 
@@ -1853,8 +1858,10 @@
     @GuardedBy("ImfLock.class")
     private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
             IInputMethodClientInvoker clientToBeReset) {
-        if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
-                + " currentUserId=" + mSettings.getCurrentUserId());
+        if (DEBUG) {
+            Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
+                    + " currentUserId=" + mSettings.getCurrentUserId());
+        }
 
         maybeInitImeNavbarConfigLocked(newUserId);
 
@@ -1871,8 +1878,10 @@
         AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
         final String defaultImiId = mSettings.getSelectedInputMethod();
 
-        if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
-                + " defaultImiId=" + defaultImiId);
+        if (DEBUG) {
+            Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
+                    + " defaultImiId=" + defaultImiId);
+        }
 
         // For secondary users, the list of enabled IMEs may not have been updated since the
         // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
@@ -1899,8 +1908,10 @@
                     mSettings.getEnabledInputMethodListLocked());
         }
 
-        if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
-                + " selectedIme=" + mSettings.getSelectedInputMethod());
+        if (DEBUG) {
+            Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
+                    + " selectedIme=" + mSettings.getSelectedInputMethod());
+        }
 
         mLastSwitchUserId = newUserId;
 
@@ -1910,7 +1921,7 @@
                 // The client is already gone.
                 return;
             }
-            cs.client.scheduleStartInputIfNecessary(mInFullscreenMode);
+            cs.mClient.scheduleStartInputIfNecessary(mInFullscreenMode);
         }
     }
 
@@ -1934,6 +1945,9 @@
         }
     }
 
+    /**
+     * TODO(b/32343335): The entire systemRunning() method needs to be revisited.
+     */
     public void systemRunning(StatusBarManagerService statusBar) {
         synchronized (ImfLock.class) {
             if (DEBUG) {
@@ -2033,7 +2047,7 @@
         // by a token.
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-                        == PackageManager.PERMISSION_GRANTED) {
+                == PackageManager.PERMISSION_GRANTED) {
             if (DEBUG) {
                 Slog.d(TAG, "--- Access granted because the calling process has "
                         + "the INTERACT_ACROSS_USERS_FULL permission");
@@ -2270,8 +2284,8 @@
             final int numClients = mClients.size();
             for (int i = 0; i < numClients; ++i) {
                 final ClientState state = mClients.valueAt(i);
-                if (state.uid == callerUid && state.pid == callerPid
-                        && state.selfReportedDisplayId == selfReportedDisplayId) {
+                if (state.mUid == callerUid && state.mPid == callerPid
+                        && state.mSelfReportedDisplayId == selfReportedDisplayId) {
                     throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
                             + "/displayId=" + selfReportedDisplayId + " is already registered.");
                 }
@@ -2303,7 +2317,7 @@
         synchronized (ImfLock.class) {
             ClientState cs = mClients.remove(client.asBinder());
             if (cs != null) {
-                client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
+                client.asBinder().unlinkToDeath(cs.mClientDeathRecipient, 0);
                 clearClientSessionLocked(cs);
                 clearClientSessionForAccessibilityLocked(cs);
 
@@ -2342,8 +2356,10 @@
     @GuardedBy("ImfLock.class")
     void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
         if (mCurClient != null) {
-            if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
-                    + mCurClient.client.asBinder());
+            if (DEBUG) {
+                Slog.v(TAG, "unbindCurrentInputLocked: client="
+                        + mCurClient.mClient.asBinder());
+            }
             if (mBoundToMethod) {
                 mBoundToMethod = false;
                 IInputMethodInvoker curMethod = getCurMethodLocked();
@@ -2356,10 +2372,10 @@
             // Since we set active false to current client and set mCurClient to null, let's unbind
             // all accessibility too. That means, when input method get disconnected (including
             // switching ime), we also unbind accessibility
-            mCurClient.client.setActive(false /* active */, false /* fullscreen */,
+            mCurClient.mClient.setActive(false /* active */, false /* fullscreen */,
                     false /* reportToImeController */);
-            mCurClient.client.onUnbindMethod(getSequenceNumberLocked(), unbindClientReason);
-            mCurClient.sessionRequested = false;
+            mCurClient.mClient.onUnbindMethod(getSequenceNumberLocked(), unbindClientReason);
+            mCurClient.mSessionRequested = false;
             mCurClient.mSessionRequestedForAccessibility = false;
             mCurClient = null;
             mCurVirtualDisplayToScreenMatrix = null;
@@ -2401,7 +2417,7 @@
     @NonNull
     InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
         if (!mBoundToMethod) {
-            getCurMethodLocked().bindInput(mCurClient.binding);
+            getCurMethodLocked().bindInput(mCurClient.mBinding);
             mBoundToMethod = true;
         }
 
@@ -2410,7 +2426,7 @@
         final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(),
                 getCurTokenLocked(),
                 mCurTokenDisplayId, getCurIdLocked(), startInputReason, restarting,
-                UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
+                UserHandle.getUserId(mCurClient.mUid), mCurClient.mSelfReportedDisplayId,
                 mCurFocusedWindow, mCurEditorInfo, mCurFocusedWindowSoftInputMode,
                 getSequenceNumberLocked());
         mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
@@ -2421,17 +2437,17 @@
         // same-user scenarios.
         // That said ignoring cross-user scenario will never affect IMEs that do not have
         // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
-        if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.uid)) {
+        if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.mUid)) {
             mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(),
-                    null /* intent */, UserHandle.getAppId(getCurMethodUidLocked()), mCurClient.uid,
-                    true /* direct */);
+                    null /* intent */, UserHandle.getAppId(getCurMethodUidLocked()),
+                    mCurClient.mUid, true /* direct */);
         }
 
         @InputMethodNavButtonFlags
         final int navButtonFlags = getInputMethodNavButtonFlagsLocked();
-        final SessionState session = mCurClient.curSession;
+        final SessionState session = mCurClient.mCurSession;
         setEnabledSessionLocked(session);
-        session.method.startInput(startInputToken, mCurInputConnection, mCurEditorInfo, restarting,
+        session.mMethod.startInput(startInputToken, mCurInputConnection, mCurEditorInfo, restarting,
                 navButtonFlags, mCurImeDispatcher);
         if (mShowRequested) {
             if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
@@ -2446,8 +2462,8 @@
         final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions =
                 createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
         return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
-                session.session, accessibilityInputMethodSessions,
-                (session.channel != null ? session.channel.dup() : null),
+                session.mSession, accessibilityInputMethodSessions,
+                (session.mChannel != null ? session.mChannel.dup() : null),
                 curId, getSequenceNumberLocked(), mCurVirtualDisplayToScreenMatrix,
                 suppressesSpellChecker);
     }
@@ -2470,10 +2486,10 @@
             } else {
                 matrix.postConcat(info.mMatrix);
             }
-            if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
+            if (info.mParentClient.mSelfReportedDisplayId == imeDisplayId) {
                 return matrix;
             }
-            displayId = info.mParentClient.selfReportedDisplayId;
+            displayId = info.mParentClient.mSelfReportedDisplayId;
         }
     }
 
@@ -2541,16 +2557,16 @@
                     null, null, null, selectedMethodId, getSequenceNumberLocked(), null, false);
         }
 
-        if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
+        if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.mUid,
                 editorInfo.packageName)) {
             Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
-                    + " uid=" + cs.uid + " package=" + editorInfo.packageName);
+                    + " uid=" + cs.mUid + " package=" + editorInfo.packageName);
             return InputBindResult.INVALID_PACKAGE_NAME;
         }
 
         // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
         // session & other conditions.
-        mDisplayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
+        mDisplayIdToShowIme = computeImeDisplayIdForTarget(cs.mSelfReportedDisplayId,
                 mImeDisplayValidator);
 
         if (mDisplayIdToShowIme == INVALID_DISPLAY) {
@@ -2572,7 +2588,7 @@
         mCurRemoteAccessibilityInputConnection = remoteAccessibilityInputConnection;
         mCurImeDispatcher = imeDispatcher;
         mCurVirtualDisplayToScreenMatrix =
-                getVirtualDisplayToScreenMatrixLocked(cs.selfReportedDisplayId,
+                getVirtualDisplayToScreenMatrixLocked(cs.mSelfReportedDisplayId,
                         mDisplayIdToShowIme);
         mCurEditorInfo = editorInfo;
 
@@ -2591,7 +2607,7 @@
         // We expect the caller has already verified that the client is allowed to access this
         // display ID.
         if (isSelectedMethodBoundLocked()) {
-            if (cs.curSession != null) {
+            if (cs.mCurSession != null) {
                 // Fast case: if we are already connected to the input method,
                 // then just return it.
                 // This doesn't mean a11y sessions are there. When a11y service is
@@ -2667,7 +2683,7 @@
         unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
         // If the screen is on, inform the new client it is active
         if (mIsInteractive) {
-            cs.client.setActive(true /* active */, false /* fullscreen */,
+            cs.mClient.setActive(true /* active */, false /* fullscreen */,
                     false /* reportToImeController */);
         }
     }
@@ -2779,13 +2795,13 @@
                         && curMethod.asBinder() == method.asBinder()) {
                     if (mCurClient != null) {
                         clearClientSessionLocked(mCurClient);
-                        mCurClient.curSession = new SessionState(mCurClient,
+                        mCurClient.mCurSession = new SessionState(mCurClient,
                                 method, session, channel);
                         InputBindResult res = attachNewInputLocked(
                                 StartInputReason.SESSION_CREATED_BY_IME, true);
                         attachNewAccessibilityLocked(StartInputReason.SESSION_CREATED_BY_IME, true);
                         if (res.method != null) {
-                            mCurClient.client.onBindMethod(res);
+                            mCurClient.mClient.onBindMethod(res);
                         }
                         return;
                     }
@@ -2828,7 +2844,7 @@
 
     @GuardedBy("ImfLock.class")
     void requestClientSessionLocked(ClientState cs) {
-        if (!cs.sessionRequested) {
+        if (!cs.mSessionRequested) {
             if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
             final InputChannel serverChannel;
             final InputChannel clientChannel;
@@ -2838,7 +2854,7 @@
                 clientChannel = channels[1];
             }
 
-            cs.sessionRequested = true;
+            cs.mSessionRequested = true;
 
             final IInputMethodInvoker curMethod = getCurMethodLocked();
             final IInputMethodSessionCallback.Stub callback =
@@ -2881,9 +2897,9 @@
 
     @GuardedBy("ImfLock.class")
     void clearClientSessionLocked(ClientState cs) {
-        finishSessionLocked(cs.curSession);
-        cs.curSession = null;
-        cs.sessionRequested = false;
+        finishSessionLocked(cs.mCurSession);
+        cs.mCurSession = null;
+        cs.mSessionRequested = false;
     }
 
     @GuardedBy("ImfLock.class")
@@ -2907,18 +2923,18 @@
     @GuardedBy("ImfLock.class")
     private void finishSessionLocked(SessionState sessionState) {
         if (sessionState != null) {
-            if (sessionState.session != null) {
+            if (sessionState.mSession != null) {
                 try {
-                    sessionState.session.finishSession();
+                    sessionState.mSession.finishSession();
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Session failed to close due to remote exception", e);
                     updateSystemUiLocked(0 /* vis */, mBackDisposition);
                 }
-                sessionState.session = null;
+                sessionState.mSession = null;
             }
-            if (sessionState.channel != null) {
-                sessionState.channel.dispose();
-                sessionState.channel = null;
+            if (sessionState.mChannel != null) {
+                sessionState.mChannel.dispose();
+                sessionState.mChannel = null;
             }
         }
     }
@@ -3017,7 +3033,7 @@
                 InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE);
         return (canImeDrawsImeNavBar ? InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR : 0)
                 | (shouldShowImeSwitcherWhenImeIsShown
-                        ? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0);
+                ? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0);
     }
 
     @GuardedBy("ImfLock.class")
@@ -3040,17 +3056,17 @@
             return false;
         }
 
-        List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListWithFilterLocked(
+        List<InputMethodInfo> imes = mSettings.getEnabledInputMethodListWithFilterLocked(
                 InputMethodInfo::shouldShowInInputMethodPicker);
-        final int N = imis.size();
-        if (N > 2) return true;
-        if (N < 1) return false;
+        final int numImes = imes.size();
+        if (numImes > 2) return true;
+        if (numImes < 1) return false;
         int nonAuxCount = 0;
         int auxCount = 0;
         InputMethodSubtype nonAuxSubtype = null;
         InputMethodSubtype auxSubtype = null;
-        for(int i = 0; i < N; ++i) {
-            final InputMethodInfo imi = imis.get(i);
+        for (int i = 0; i < numImes; ++i) {
+            final InputMethodInfo imi = imes.get(i);
             final List<InputMethodSubtype> subtypes =
                     mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
             final int subtypeCount = subtypes.size();
@@ -3074,8 +3090,8 @@
         } else if (nonAuxCount == 1 && auxCount == 1) {
             if (nonAuxSubtype != null && auxSubtype != null
                     && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
-                            || auxSubtype.overridesImplicitlyEnabledSubtype()
-                            || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
+                    || auxSubtype.overridesImplicitlyEnabledSubtype()
+                    || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
                     && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
                 return false;
             }
@@ -3231,7 +3247,7 @@
     void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
         if (enabledMayChange) {
             List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
-            for (int i=0; i<enabled.size(); i++) {
+            for (int i = 0; i < enabled.size(); i++) {
                 // We allow the user to select "disabled until used" apps, so if they
                 // are enabling one of those here we now need to make it enabled.
                 InputMethodInfo imm = enabled.get(i);
@@ -3437,10 +3453,10 @@
             return false;
         }
 
-        if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
+        if ((flags & InputMethodManager.SHOW_FORCED) != 0) {
             mShowExplicitlyRequested = true;
             mShowForced = true;
-        } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
+        } else if ((flags & InputMethodManager.SHOW_IMPLICIT) == 0) {
             mShowExplicitlyRequested = true;
         }
 
@@ -3496,12 +3512,12 @@
     @GuardedBy("ImfLock.class")
     boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
-        if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
+        if ((flags & InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
                 && (mShowExplicitlyRequested || mShowForced)) {
             if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
             return false;
         }
-        if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
+        if (mShowForced && (flags & InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
             if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
             return false;
         }
@@ -3548,7 +3564,7 @@
 
     private boolean isImeClientFocused(IBinder windowToken, ClientState cs) {
         final int imeClientFocus = mWindowManagerInternal.hasInputMethodClientFocus(
-                windowToken, cs.uid, cs.pid, cs.selfReportedDisplayId);
+                windowToken, cs.mUid, cs.mPid, cs.mSelfReportedDisplayId);
         return imeClientFocus == WindowManagerInternal.ImeClientFocusResult.HAS_IME_FOCUS;
     }
 
@@ -3663,7 +3679,7 @@
         }
 
         final int imeClientFocus = mWindowManagerInternal.hasInputMethodClientFocus(
-                windowToken, cs.uid, cs.pid, cs.selfReportedDisplayId);
+                windowToken, cs.mUid, cs.mPid, cs.mSelfReportedDisplayId);
         switch (imeClientFocus) {
             case WindowManagerInternal.ImeClientFocusResult.DISPLAY_ID_MISMATCH:
                 Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch.");
@@ -3675,8 +3691,8 @@
                 // next client receiving focus that has any interest in input will
                 // be calling through here after that change happens.
                 if (DEBUG) {
-                    Slog.w(TAG, "Focus gain on non-focused client " + cs.client
-                            + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+                    Slog.w(TAG, "Focus gain on non-focused client " + cs.mClient
+                            + " (uid=" + cs.mUid + " pid=" + cs.mPid + ")");
                 }
                 return InputBindResult.NOT_IME_TARGET_WINDOW;
             case WindowManagerInternal.ImeClientFocusResult.INVALID_DISPLAY_ID:
@@ -3687,19 +3703,19 @@
             // There is already an on-going pending user switch task.
             final int nextUserId = mUserSwitchHandlerTask.mToUserId;
             if (userId == nextUserId) {
-                scheduleSwitchUserTaskLocked(userId, cs.client);
+                scheduleSwitchUserTaskLocked(userId, cs.mClient);
                 return InputBindResult.USER_SWITCHING;
             }
             for (int profileId : mUserManager.getProfileIdsWithDisabled(nextUserId)) {
                 if (profileId == userId) {
-                    scheduleSwitchUserTaskLocked(userId, cs.client);
+                    scheduleSwitchUserTaskLocked(userId, cs.mClient);
                     return InputBindResult.USER_SWITCHING;
                 }
             }
             return InputBindResult.INVALID_USER;
         }
 
-        final boolean shouldClearFlag = mImePlatformCompatUtils.shouldClearShowForcedFlag(cs.uid);
+        final boolean shouldClearFlag = mImePlatformCompatUtils.shouldClearShowForcedFlag(cs.mUid);
         // In case mShowForced flag affects the next client to keep IME visible, when the current
         // client is leaving due to the next focused client, we clear mShowForced flag when the
         // next client's targetSdkVersion is T or higher.
@@ -3719,7 +3735,7 @@
         }
 
         if (userId != mSettings.getCurrentUserId()) {
-            scheduleSwitchUserTaskLocked(userId, cs.client);
+            scheduleSwitchUserTaskLocked(userId, cs.mClient);
             return InputBindResult.USER_SWITCHING;
         }
 
@@ -3760,7 +3776,7 @@
         final boolean doAutoShow =
                 (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
                         == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
-                || mRes.getConfiguration().isLayoutSizeAtLeast(
+                        || mRes.getConfiguration().isLayoutSizeAtLeast(
                         Configuration.SCREENLAYOUT_SIZE_LARGE);
 
         // We want to start input before showing the IME, but after closing
@@ -3803,7 +3819,7 @@
                         // window token removed.
                         // Note that we can trust client's display ID as long as it matches
                         // to the display ID obtained from the window.
-                        if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
+                        if (cs.mSelfReportedDisplayId != mCurTokenDisplayId) {
                             mBindingController.unbindCurrentMethod();
                         }
                     }
@@ -3918,7 +3934,7 @@
     private boolean canInteractWithImeLocked(
             int uid, IInputMethodClient client, String methodName) {
         if (mCurClient == null || client == null
-                || mCurClient.client.asBinder() != client.asBinder()) {
+                || mCurClient.mClient.asBinder() != client.asBinder()) {
             // We need to check if this is the current client with
             // focus in the window manager, to allow this call to
             // be made before input is started in it.
@@ -3951,7 +3967,7 @@
     private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
         final int uid = Binder.getCallingUid();
         if (mCurFocusedWindowClient != null && client != null
-                && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
+                && mCurFocusedWindowClient.mClient.asBinder() == client.asBinder()) {
             return true;
         }
         if (mSettings.getCurrentUserId() != UserHandle.getUserId(uid)) {
@@ -3979,7 +3995,7 @@
             // Always call subtype picker, because subtype picker is a superset of input method
             // picker.
             final int displayId =
-                    (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY;
+                    (mCurClient != null) ? mCurClient.mSelfReportedDisplayId : DEFAULT_DISPLAY;
             mHandler.obtainMessage(MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId)
                     .sendToTarget();
         }
@@ -4078,11 +4094,11 @@
                 // the most applicable enabled keyboard subtype of the system imes.
                 final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
                 if (enabled != null) {
-                    final int N = enabled.size();
+                    final int enabledCount = enabled.size();
                     final String locale = mCurrentSubtype == null
                             ? mRes.getConfiguration().locale.toString()
                             : mCurrentSubtype.getLocale();
-                    for (int i = 0; i < N; ++i) {
+                    for (int i = 0; i < enabledCount; ++i) {
                         final InputMethodInfo imi = enabled.get(i);
                         if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
                             InputMethodSubtype keyboardSubtype =
@@ -4093,7 +4109,7 @@
                                 targetLastImiId = imi.getId();
                                 subtypeId = SubtypeUtils.getSubtypeIdFromHashCode(imi,
                                         keyboardSubtype.hashCode());
-                                if(keyboardSubtype.getLocale().equals(locale)) {
+                                if (keyboardSubtype.getLocale().equals(locale)) {
                                     break;
                                 }
                             }
@@ -4230,8 +4246,9 @@
      * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
      * {@link InputMethodService#onCreate()}.
      *
-     * <p>TODO(Bug 113914148): Check if we can remove this.</p>
      * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
+     *
+     * @deprecated TODO(b/113914148): Check if we can remove this
      */
     @Override
     @Deprecated
@@ -4305,7 +4322,7 @@
                             + " is already registered by " + info.mParentClient);
                 }
                 if (info == null) {
-                    if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
+                    if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.mUid)) {
                         throw new SecurityException(cs + " cannot access to display #"
                                 + childDisplayId);
                     }
@@ -4314,12 +4331,12 @@
                 }
                 info.mMatrix.setValues(matrixValues);
 
-                if (mCurClient == null || mCurClient.curSession == null) {
+                if (mCurClient == null || mCurClient.mCurSession == null) {
                     return;
                 }
 
                 Matrix matrix = null;
-                int displayId = mCurClient.selfReportedDisplayId;
+                int displayId = mCurClient.mSelfReportedDisplayId;
                 boolean needToNotify = false;
                 while (true) {
                     needToNotify |= (displayId == childDisplayId);
@@ -4332,16 +4349,16 @@
                     } else {
                         matrix.postConcat(next.mMatrix);
                     }
-                    if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
+                    if (next.mParentClient.mSelfReportedDisplayId == mCurTokenDisplayId) {
                         if (needToNotify) {
                             final float[] values = new float[9];
                             matrix.getValues(values);
-                            mCurClient.client.updateVirtualDisplayToScreenMatrix(
+                            mCurClient.mClient.updateVirtualDisplayToScreenMatrix(
                                     getSequenceNumberLocked(), values);
                         }
                         break;
                     }
-                    displayId = info.mParentClient.selfReportedDisplayId;
+                    displayId = info.mParentClient.mSelfReportedDisplayId;
                 }
             }
         } catch (Throwable t) {
@@ -4493,7 +4510,7 @@
     /**
      * Starting point for dumping the IME tracing information in proto format.
      *
-     * @param clientProtoDump dump information from the IME client side
+     * @param protoDump dump information from the IME client side
      */
     @BinderThread
     @Override
@@ -4558,7 +4575,7 @@
         }
         for (ClientState state : clients.values()) {
             if (state != null) {
-                state.client.setImeTraceEnabled(true /* enabled */);
+                state.mClient.setImeTraceEnabled(true /* enabled */);
             }
         }
     }
@@ -4573,7 +4590,7 @@
         }
         for (ClientState state : clients.values()) {
             if (state != null) {
-                state.client.setImeTraceEnabled(false /* enabled */);
+                state.mClient.setImeTraceEnabled(false /* enabled */);
             }
         }
     }
@@ -4652,7 +4669,7 @@
                     // actual IME target.
                     mWindowManagerInternal.hideIme(
                             mHideRequestWindowMap.get(windowToken),
-                            mCurClient.selfReportedDisplayId);
+                            mCurClient.mSelfReportedDisplayId);
                 }
             } else {
                 // Send to window manager to show IME after IME layout finishes.
@@ -4683,7 +4700,7 @@
                     != PackageManager.PERMISSION_GRANTED) {
                 throw new SecurityException(
                         "Using null token requires permission "
-                        + android.Manifest.permission.WRITE_SECURE_SETTINGS);
+                                + android.Manifest.permission.WRITE_SECURE_SETTINGS);
             }
         } else if (getCurTokenLocked() != token) {
             Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
@@ -4751,14 +4768,14 @@
     @GuardedBy("ImfLock.class")
     void setEnabledSessionLocked(SessionState session) {
         if (mEnabledSession != session) {
-            if (mEnabledSession != null && mEnabledSession.session != null) {
+            if (mEnabledSession != null && mEnabledSession.mSession != null) {
                 if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
-                mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
+                mEnabledSession.mMethod.setSessionEnabled(mEnabledSession.mSession, false);
             }
             mEnabledSession = session;
-            if (mEnabledSession != null && mEnabledSession.session != null) {
+            if (mEnabledSession != null && mEnabledSession.mSession != null) {
                 if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
-                mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
+                mEnabledSession.mMethod.setSessionEnabled(mEnabledSession.mSession, true);
             }
         }
     }
@@ -4837,9 +4854,9 @@
             case MSG_REMOVE_IME_SURFACE: {
                 synchronized (ImfLock.class) {
                     try {
-                        if (mEnabledSession != null && mEnabledSession.session != null
+                        if (mEnabledSession != null && mEnabledSession.mSession != null
                                 && !mShowRequested) {
-                            mEnabledSession.session.removeImeSurface();
+                            mEnabledSession.mSession.removeImeSurface();
                         }
                     } catch (RemoteException e) {
                     }
@@ -4851,8 +4868,8 @@
                 synchronized (ImfLock.class) {
                     try {
                         if (windowToken == mCurFocusedWindow
-                                && mEnabledSession != null && mEnabledSession.session != null) {
-                            mEnabledSession.session.removeImeSurface();
+                                && mEnabledSession != null && mEnabledSession.mSession != null) {
+                            mEnabledSession.mSession.removeImeSurface();
                         }
                     } catch (RemoteException e) {
                     }
@@ -4962,8 +4979,8 @@
             updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
 
             // Inform the current client of the change in active status
-            if (mCurClient != null && mCurClient.client != null) {
-                mCurClient.client.setActive(mIsInteractive, mInFullscreenMode,
+            if (mCurClient != null && mCurClient.mClient != null) {
+                mCurClient.mClient.setActive(mIsInteractive, mInFullscreenMode,
                         mImePlatformCompatUtils.shouldFinishInputWithReportToIme(
                                 getCurMethodUidLocked()));
             }
@@ -5073,8 +5090,8 @@
                     mContext.getPackageManager().queryIntentServicesAsUser(
                             new Intent(InputMethod.SERVICE_INTERFACE),
                             PackageManager.MATCH_DISABLED_COMPONENTS, mSettings.getCurrentUserId());
-            final int N = allInputMethodServices.size();
-            for (int i = 0; i < N; ++i) {
+            final int numImes = allInputMethodServices.size();
+            for (int i = 0; i < numImes; ++i) {
                 final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
                 if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
                     mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
@@ -5088,8 +5105,8 @@
             boolean enabledImeFound = false;
             boolean enabledNonAuxImeFound = false;
             final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
-            final int N = enabledImes.size();
-            for (int i = 0; i < N; ++i) {
+            final int numImes = enabledImes.size();
+            for (int i = 0; i < numImes; ++i) {
                 final InputMethodInfo imi = enabledImes.get(i);
                 if (mMethodList.contains(imi)) {
                     enabledImeFound = true;
@@ -5117,8 +5134,8 @@
             final ArrayList<InputMethodInfo> defaultEnabledIme =
                     InputMethodInfoUtils.getDefaultEnabledImes(mContext, mMethodList,
                             reenableMinimumNonAuxSystemImes);
-            final int N = defaultEnabledIme.size();
-            for (int i = 0; i < N; ++i) {
+            final int numImes = defaultEnabledIme.size();
+            for (int i = 0; i < numImes; ++i) {
                 final InputMethodInfo imi =  defaultEnabledIme.get(i);
                 if (DEBUG) {
                     Slog.d(TAG, "--- enable ime = " + imi);
@@ -5360,7 +5377,7 @@
         if (userId == mSettings.getCurrentUserId()) {
             if (!mMethodMap.containsKey(imeId)
                     || !mSettings.getEnabledInputMethodListLocked()
-                            .contains(mMethodMap.get(imeId))) {
+                    .contains(mMethodMap.get(imeId))) {
                 return false; // IME is not found or not enabled.
             }
             setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
@@ -5371,8 +5388,7 @@
                 mContext.getResources(), mContext.getContentResolver(), methodMap,
                 userId, false);
         if (!methodMap.containsKey(imeId)
-                || !settings.getEnabledInputMethodListLocked()
-                        .contains(methodMap.get(imeId))) {
+                || !settings.getEnabledInputMethodListLocked().contains(methodMap.get(imeId))) {
             return false; // IME is not found or not enabled.
         }
         settings.putSelectedInputMethod(imeId);
@@ -5528,18 +5544,18 @@
                     attachNewAccessibilityLocked(StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY,
                             true);
 
-                    final SessionState sessionState = mCurClient.curSession;
+                    final SessionState sessionState = mCurClient.mCurSession;
                     final IInputMethodSession imeSession = sessionState == null
-                            ? null : sessionState.session;
+                            ? null : sessionState.mSession;
                     final SparseArray<IAccessibilityInputMethodSession>
                             accessibilityInputMethodSessions =
-                                    createAccessibilityInputMethodSessions(
-                                            mCurClient.mAccessibilitySessions);
+                            createAccessibilityInputMethodSessions(
+                                    mCurClient.mAccessibilitySessions);
                     final InputBindResult res = new InputBindResult(
                             InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
                             imeSession, accessibilityInputMethodSessions, null, getCurIdLocked(),
                             getSequenceNumberLocked(), mCurVirtualDisplayToScreenMatrix, false);
-                    mCurClient.client.onBindAccessibilityService(res, accessibilityConnectionId);
+                    mCurClient.mClient.onBindAccessibilityService(res, accessibilityConnectionId);
                 }
             }
         }
@@ -5550,11 +5566,11 @@
                 if (mCurClient != null) {
                     if (DEBUG) {
                         Slog.v(TAG, "unbindAccessibilityFromCurrentClientLocked: client="
-                                + mCurClient.client.asBinder());
+                                + mCurClient.mClient.asBinder());
                     }
                     // A11yManagerService unbinds the disabled accessibility service. We don't need
                     // to do it here.
-                    mCurClient.client.onUnbindAccessibilityService(getSequenceNumberLocked(),
+                    mCurClient.mClient.onUnbindAccessibilityService(getSequenceNumberLocked(),
                             accessibilityConnectionId);
                 }
                 // We only have sessions when we bound to an input method. Remove this session
@@ -5620,7 +5636,7 @@
             // This user ID can never bee spoofed.
             final int imeUserId = UserHandle.getUserId(uid);
             // This user ID can never bee spoofed.
-            final int appUserId = UserHandle.getUserId(mCurClient.uid);
+            final int appUserId = UserHandle.getUserId(mCurClient.mUid);
             // This user ID may be invalid if "contentUri" embedded an invalid user ID.
             final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
                     imeUserId);
@@ -5642,9 +5658,9 @@
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
-            if (mCurClient != null && mCurClient.client != null) {
+            if (mCurClient != null && mCurClient.mClient != null) {
                 mInFullscreenMode = fullscreen;
-                mCurClient.client.reportFullscreenMode(fullscreen);
+                mCurClient.mClient.reportFullscreenMode(fullscreen);
             }
         }
     }
@@ -5722,9 +5738,9 @@
 
         synchronized (ImfLock.class) {
             p.println("Current Input Method Manager state:");
-            int N = mMethodList.size();
+            int numImes = mMethodList.size();
             p.println("  Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
-            for (int i=0; i<N; i++) {
+            for (int i = 0; i < numImes; i++) {
                 InputMethodInfo info = mMethodList.get(i);
                 p.println("  InputMethod #" + i + ":");
                 info.dump(p, "    ");
@@ -5734,20 +5750,20 @@
             for (int i = 0; i < numClients; ++i) {
                 final ClientState ci = mClients.valueAt(i);
                 p.println("  Client " + ci + ":");
-                p.println("    client=" + ci.client);
-                p.println("    fallbackInputConnection=" + ci.fallbackInputConnection);
-                p.println("    sessionRequested=" + ci.sessionRequested);
+                p.println("    client=" + ci.mClient);
+                p.println("    fallbackInputConnection=" + ci.mFallbackInputConnection);
+                p.println("    sessionRequested=" + ci.mSessionRequested);
                 p.println("    sessionRequestedForAccessibility="
                         + ci.mSessionRequestedForAccessibility);
-                p.println("    curSession=" + ci.curSession);
+                p.println("    curSession=" + ci.mCurSession);
             }
             p.println("  mCurMethodId=" + getSelectedMethodIdLocked());
             client = mCurClient;
             p.println("  mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
             p.println("  mCurPerceptible=" + mCurPerceptible);
             p.println("  mCurFocusedWindow=" + mCurFocusedWindow
-                    + " softInputMode=" +
-                    InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
+                    + " softInputMode="
+                    + InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
                     + " client=" + mCurFocusedWindowClient);
             focusedWindowClient = mCurFocusedWindowClient;
             p.println("  mCurId=" + getCurIdLocked() + " mHaveConnection=" + hasConnectionLocked()
@@ -5791,7 +5807,7 @@
         if (client != null) {
             pw.flush();
             try {
-                TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
+                TransferPipe.dumpAsync(client.mClient.asBinder(), fd, args);
             } catch (IOException | RemoteException e) {
                 p.println("Failed to dump input method client: " + e);
             }
@@ -5807,7 +5823,7 @@
             p.println(" ");
             pw.flush();
             try {
-                TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
+                TransferPipe.dumpAsync(focusedWindowClient.mClient.asBinder(), fd, args);
             } catch (IOException | RemoteException e) {
                 p.println("Failed to dump input method client in focused window: " + e);
             }
@@ -6359,7 +6375,7 @@
         }
         for (ClientState state : clients.values()) {
             if (state != null) {
-                state.client.setImeTraceEnabled(isImeTraceEnabled);
+                state.mClient.setImeTraceEnabled(isImeTraceEnabled);
             }
         }
         return ShellCommandResult.SUCCESS;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1369f27..172cf29 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2460,11 +2460,11 @@
         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> {
             try {
                 if (DBG) {
-                    Slog.d(TAG, "Reposting " + r.getKey());
+                    Slog.d(TAG, "Reposting " + r.getKey() + " " + muteOnReturn);
                 }
                 enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
                         r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
-                        r.getSbn().getId(),  r.getSbn().getNotification(), userId, true);
+                        r.getSbn().getId(),  r.getSbn().getNotification(), userId, muteOnReturn);
             } catch (Exception e) {
                 Slog.e(TAG, "Cannot un-snooze notification", e);
             }
diff --git a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
index 683eaeb..372bcc6 100644
--- a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
@@ -46,9 +46,10 @@
 
     private final boolean mAutoDetectionSupported;
     private final int mSystemClockUpdateThresholdMillis;
-    private final Instant mAutoTimeLowerBound;
+    private final Instant mAutoSuggestionLowerBound;
+    private final Instant mManualSuggestionLowerBound;
+    private final Instant mSuggestionUpperBound;
     private final @Origin int[] mOriginPriorities;
-    private final boolean mDeviceHasY2038Issue;
     private final boolean mAutoDetectionEnabledSetting;
     private final @UserIdInt int mUserId;
     private final boolean mUserConfigAllowed;
@@ -56,9 +57,10 @@
     private ConfigurationInternal(Builder builder) {
         mAutoDetectionSupported = builder.mAutoDetectionSupported;
         mSystemClockUpdateThresholdMillis = builder.mSystemClockUpdateThresholdMillis;
-        mAutoTimeLowerBound = Objects.requireNonNull(builder.mAutoTimeLowerBound);
+        mAutoSuggestionLowerBound = Objects.requireNonNull(builder.mAutoSuggestionLowerBound);
+        mManualSuggestionLowerBound = Objects.requireNonNull(builder.mManualSuggestionLowerBound);
+        mSuggestionUpperBound = Objects.requireNonNull(builder.mSuggestionUpperBound);
         mOriginPriorities = Objects.requireNonNull(builder.mOriginPriorities);
-        mDeviceHasY2038Issue = builder.mDeviceHasY2038Issue;
         mAutoDetectionEnabledSetting = builder.mAutoDetectionEnabledSetting;
 
         mUserId = builder.mUserId;
@@ -80,14 +82,31 @@
     }
 
     /**
-     * Returns the lower bound for valid automatic times. It is guaranteed to be in the past,
-     * i.e. it is unrelated to the current system clock time.
+     * Returns the lower bound for valid automatic time suggestions. It is guaranteed to be in the
+     * past, i.e. it is unrelated to the current system clock time.
      * It holds no other meaning; it could be related to when the device system image was built,
      * or could be updated by a mainline module.
      */
     @NonNull
-    public Instant getAutoTimeLowerBound() {
-        return mAutoTimeLowerBound;
+    public Instant getAutoSuggestionLowerBound() {
+        return mAutoSuggestionLowerBound;
+    }
+
+    /**
+     * Returns the lower bound for valid manual time suggestions. It is guaranteed to be in the
+     * past, i.e. it is unrelated to the current system clock time.
+     */
+    @NonNull
+    public Instant getManualSuggestionLowerBound() {
+        return mManualSuggestionLowerBound;
+    }
+
+    /**
+     * Returns the upper bound for valid time suggestions (manual and automatic).
+     */
+    @NonNull
+    public Instant getSuggestionUpperBound() {
+        return mSuggestionUpperBound;
     }
 
     /**
@@ -98,14 +117,6 @@
         return mOriginPriorities;
     }
 
-    /**
-     * Returns {@code true} if the device may be at risk of time_t overflow (because bionic
-     * defines time_t as a 32-bit signed integer for 32-bit processes).
-     */
-    public boolean getDeviceHasY2038Issue() {
-        return mDeviceHasY2038Issue;
-    }
-
     /** Returns the value of the auto time detection enabled setting. */
     public boolean getAutoDetectionEnabledSetting() {
         return mAutoDetectionEnabledSetting;
@@ -207,16 +218,17 @@
                 && mAutoDetectionEnabledSetting == that.mAutoDetectionEnabledSetting
                 && mUserId == that.mUserId && mUserConfigAllowed == that.mUserConfigAllowed
                 && mSystemClockUpdateThresholdMillis == that.mSystemClockUpdateThresholdMillis
-                && mAutoTimeLowerBound.equals(that.mAutoTimeLowerBound)
-                && mDeviceHasY2038Issue == that.mDeviceHasY2038Issue
+                && mAutoSuggestionLowerBound.equals(that.mAutoSuggestionLowerBound)
+                && mManualSuggestionLowerBound.equals(that.mManualSuggestionLowerBound)
+                && mSuggestionUpperBound.equals(that.mSuggestionUpperBound)
                 && Arrays.equals(mOriginPriorities, that.mOriginPriorities);
     }
 
     @Override
     public int hashCode() {
         int result = Objects.hash(mAutoDetectionSupported, mAutoDetectionEnabledSetting, mUserId,
-                mUserConfigAllowed, mSystemClockUpdateThresholdMillis, mAutoTimeLowerBound,
-                mDeviceHasY2038Issue);
+                mUserConfigAllowed, mSystemClockUpdateThresholdMillis, mAutoSuggestionLowerBound,
+                mManualSuggestionLowerBound, mSuggestionUpperBound);
         result = 31 * result + Arrays.hashCode(mOriginPriorities);
         return result;
     }
@@ -230,10 +242,13 @@
         return "ConfigurationInternal{"
                 + "mAutoDetectionSupported=" + mAutoDetectionSupported
                 + ", mSystemClockUpdateThresholdMillis=" + mSystemClockUpdateThresholdMillis
-                + ", mAutoTimeLowerBound=" + mAutoTimeLowerBound
-                + "(" + mAutoTimeLowerBound.toEpochMilli() + ")"
+                + ", mAutoSuggestionLowerBound=" + mAutoSuggestionLowerBound
+                + "(" + mAutoSuggestionLowerBound.toEpochMilli() + ")"
+                + ", mManualSuggestionLowerBound=" + mManualSuggestionLowerBound
+                + "(" + mManualSuggestionLowerBound.toEpochMilli() + ")"
+                + ", mSuggestionUpperBound=" + mSuggestionUpperBound
+                + "(" + mSuggestionUpperBound.toEpochMilli() + ")"
                 + ", mOriginPriorities=" + originPrioritiesString
-                + ", mDeviceHasY2038Issue=" + mDeviceHasY2038Issue
                 + ", mAutoDetectionEnabled=" + mAutoDetectionEnabledSetting
                 + ", mUserId=" + mUserId
                 + ", mUserConfigAllowed=" + mUserConfigAllowed
@@ -243,9 +258,10 @@
     static final class Builder {
         private boolean mAutoDetectionSupported;
         private int mSystemClockUpdateThresholdMillis;
-        @NonNull private Instant mAutoTimeLowerBound;
+        @NonNull private Instant mAutoSuggestionLowerBound;
+        @NonNull private Instant mManualSuggestionLowerBound;
+        @NonNull private Instant mSuggestionUpperBound;
         @NonNull private @Origin int[] mOriginPriorities;
-        private boolean mDeviceHasY2038Issue;
         private boolean mAutoDetectionEnabledSetting;
 
         private final @UserIdInt int mUserId;
@@ -263,9 +279,10 @@
             this.mUserConfigAllowed = toCopy.mUserConfigAllowed;
             this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported;
             this.mSystemClockUpdateThresholdMillis = toCopy.mSystemClockUpdateThresholdMillis;
-            this.mAutoTimeLowerBound = toCopy.mAutoTimeLowerBound;
+            this.mAutoSuggestionLowerBound = toCopy.mAutoSuggestionLowerBound;
+            this.mManualSuggestionLowerBound = toCopy.mManualSuggestionLowerBound;
+            this.mSuggestionUpperBound = toCopy.mSuggestionUpperBound;
             this.mOriginPriorities = toCopy.mOriginPriorities;
-            this.mDeviceHasY2038Issue = toCopy.mDeviceHasY2038Issue;
             this.mAutoDetectionEnabledSetting = toCopy.mAutoDetectionEnabledSetting;
         }
 
@@ -296,10 +313,26 @@
         }
 
         /**
-         * Sets the lower bound for valid automatic times.
+         * Sets the lower bound for valid automatic time suggestions.
          */
-        public Builder setAutoTimeLowerBound(@NonNull Instant autoTimeLowerBound) {
-            mAutoTimeLowerBound = Objects.requireNonNull(autoTimeLowerBound);
+        public Builder setAutoSuggestionLowerBound(@NonNull Instant autoSuggestionLowerBound) {
+            mAutoSuggestionLowerBound = Objects.requireNonNull(autoSuggestionLowerBound);
+            return this;
+        }
+
+        /**
+         * Sets the lower bound for valid manual time suggestions.
+         */
+        public Builder setManualSuggestionLowerBound(@NonNull Instant manualSuggestionLowerBound) {
+            mManualSuggestionLowerBound = Objects.requireNonNull(manualSuggestionLowerBound);
+            return this;
+        }
+
+        /**
+         * Sets the upper bound for valid time suggestions (manual and automatic).
+         */
+        public Builder setSuggestionUpperBound(@NonNull Instant suggestionUpperBound) {
+            mSuggestionUpperBound = Objects.requireNonNull(suggestionUpperBound);
             return this;
         }
 
@@ -320,15 +353,6 @@
             return this;
         }
 
-        /**
-         * Returns {@code true} if the device may be at risk of time_t overflow (because bionic
-         * defines time_t as a 32-bit signed integer for 32-bit processes).
-         */
-        Builder setDeviceHasY2038Issue(boolean deviceHasY2038Issue) {
-            mDeviceHasY2038Issue = deviceHasY2038Issue;
-            return this;
-        }
-
         /** Returns a new {@link ConfigurationInternal}. */
         @NonNull
         ConfigurationInternal build() {
diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
index e4f3a80..888304a 100644
--- a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
@@ -31,6 +31,7 @@
 import android.app.time.TimeCapabilities;
 import android.app.time.TimeCapabilitiesAndConfig;
 import android.app.time.TimeConfiguration;
+import android.app.timedetector.TimeDetectorHelper;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -38,7 +39,6 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
-import android.os.Build;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -74,13 +74,6 @@
     private static final @Origin int[]
             DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
 
-    /**
-     * Time in the past. If an automatic time suggestion is before this point, it is sure to be
-     * incorrect.
-     */
-    private static final Instant TIME_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli(
-            Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));
-
     /** Device config keys that affect the {@link TimeDetectorService}. */
     private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Set.of(
             KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE,
@@ -237,14 +230,16 @@
     @Override
     @NonNull
     public synchronized ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+        TimeDetectorHelper timeDetectorHelper = TimeDetectorHelper.INSTANCE;
         return new ConfigurationInternal.Builder(userId)
                 .setUserConfigAllowed(isUserConfigAllowed(userId))
                 .setAutoDetectionSupported(isAutoDetectionSupported())
                 .setAutoDetectionEnabledSetting(getAutoDetectionEnabledSetting())
                 .setSystemClockUpdateThresholdMillis(getSystemClockUpdateThresholdMillis())
-                .setAutoTimeLowerBound(getAutoTimeLowerBound())
+                .setAutoSuggestionLowerBound(getAutoSuggestionLowerBound())
+                .setManualSuggestionLowerBound(timeDetectorHelper.getManualSuggestionLowerBound())
+                .setSuggestionUpperBound(timeDetectorHelper.getSuggestionUpperBound())
                 .setOriginPriorities(getOriginPriorities())
-                .setDeviceHasY2038Issue(getDeviceHasY2038Issue())
                 .build();
     }
 
@@ -291,9 +286,9 @@
     }
 
     @NonNull
-    private Instant getAutoTimeLowerBound() {
+    private Instant getAutoSuggestionLowerBound() {
         return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE)
-                .orElse(TIME_LOWER_BOUND_DEFAULT);
+                .orElse(TimeDetectorHelper.INSTANCE.getAutoSuggestionLowerBoundDefault());
     }
 
     @NonNull
@@ -310,10 +305,6 @@
         return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
     }
 
-    private boolean getDeviceHasY2038Issue() {
-        return Build.SUPPORTED_32_BIT_ABIS.length > 0;
-    }
-
     /**
      * A base supplier of an array of time origin integers in priority order.
      * It handles memoization of the result to avoid repeated string parsing when nothing has
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 017306a..547cf9d 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -84,9 +84,6 @@
      */
     private static final int KEEP_SUGGESTION_HISTORY_SIZE = 10;
 
-    /** The value in Unix epoch milliseconds of the Y2038 issue. */
-    private static final long Y2038_LIMIT_IN_MILLIS = 1000L * Integer.MAX_VALUE;
-
     /**
      * A log that records the decisions / decision metadata that affected the device's system clock
      * time. This is logged in bug reports to assist with debugging issues with detection.
@@ -248,7 +245,7 @@
 
         final TimestampedValue<Long> newUnixEpochTime = suggestion.getUnixEpochTime();
 
-        if (!validateSuggestionTime(newUnixEpochTime, suggestion)) {
+        if (!validateManualSuggestionTime(newUnixEpochTime, suggestion)) {
             return false;
         }
 
@@ -424,7 +421,7 @@
     }
 
     @GuardedBy("this")
-    private boolean validateSuggestionTime(
+    private boolean validateSuggestionCommon(
             @NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion) {
         if (newUnixEpochTime.getValue() == null) {
             Slog.w(LOG_TAG, "Suggested time value is null. suggestion=" + suggestion);
@@ -441,8 +438,8 @@
             return false;
         }
 
-        if (newUnixEpochTime.getValue() > Y2038_LIMIT_IN_MILLIS
-                && mCurrentConfigurationInternal.getDeviceHasY2038Issue()) {
+        if (newUnixEpochTime.getValue()
+                > mCurrentConfigurationInternal.getSuggestionUpperBound().toEpochMilli()) {
             // This check won't prevent a device's system clock exceeding Integer.MAX_VALUE Unix
             // seconds through the normal passage of time, but it will stop it jumping above 2038
             // because of a "bad" suggestion. b/204193177
@@ -453,20 +450,40 @@
         return true;
     }
 
+    /**
+     * Returns {@code true} if an automatic time suggestion time is valid.
+     * See also {@link #validateManualSuggestionTime(TimestampedValue, Object)}.
+     */
     @GuardedBy("this")
     private boolean validateAutoSuggestionTime(
             @NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion)  {
-        return validateSuggestionTime(newUnixEpochTime, suggestion)
-                && validateSuggestionAgainstLowerBound(newUnixEpochTime, suggestion);
+        Instant lowerBound = mCurrentConfigurationInternal.getAutoSuggestionLowerBound();
+        return validateSuggestionCommon(newUnixEpochTime, suggestion)
+                && validateSuggestionAgainstLowerBound(newUnixEpochTime, suggestion,
+                lowerBound);
+    }
+
+    /**
+     * Returns {@code true} if a manual time suggestion time is valid.
+     * See also {@link #validateAutoSuggestionTime(TimestampedValue, Object)}.
+     */
+    @GuardedBy("this")
+    private boolean validateManualSuggestionTime(
+            @NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion)  {
+        Instant lowerBound = mCurrentConfigurationInternal.getManualSuggestionLowerBound();
+
+        // Suggestion is definitely wrong if it comes before lower time bound.
+        return validateSuggestionCommon(newUnixEpochTime, suggestion)
+                && validateSuggestionAgainstLowerBound(newUnixEpochTime, suggestion, lowerBound);
     }
 
     @GuardedBy("this")
     private boolean validateSuggestionAgainstLowerBound(
-            @NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion) {
-        Instant lowerBound = mCurrentConfigurationInternal.getAutoTimeLowerBound();
+            @NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion,
+            @NonNull Instant lowerBound) {
 
         // Suggestion is definitely wrong if it comes before lower time bound.
-        if (lowerBound.isAfter(Instant.ofEpochMilli(newUnixEpochTime.getValue()))) {
+        if (lowerBound.toEpochMilli() > newUnixEpochTime.getValue()) {
             Slog.w(LOG_TAG, "Suggestion points to time before lower bound, skipping it. "
                     + "suggestion=" + suggestion + ", lower bound=" + lowerBound);
             return false;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 59dbf22..f5c5a13 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -724,13 +724,15 @@
                 // used here because it may be cleared in setTargetRootTaskIfNeeded.
                 final ActivityOptions originalOptions = mRequest.activityOptions != null
                         ? mRequest.activityOptions.getOriginalOptions() : null;
+                // Only track the launch time of activity that will be resumed.
+                final ActivityRecord launchingRecord = mDoResume ? mLastStartActivityRecord : null;
                 // If the new record is the one that started, a new activity has created.
-                final boolean newActivityCreated = mStartActivity == mLastStartActivityRecord;
+                final boolean newActivityCreated = mStartActivity == launchingRecord;
                 // Notify ActivityMetricsLogger that the activity has launched.
                 // ActivityMetricsLogger will then wait for the windows to be drawn and populate
                 // WaitResult.
                 mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
-                        newActivityCreated, mLastStartActivityRecord, originalOptions);
+                        newActivityCreated, launchingRecord, originalOptions);
                 if (mRequest.waitResult != null) {
                     mRequest.waitResult.result = res;
                     res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
@@ -1214,7 +1216,7 @@
         }
 
         mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
-                request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
+                request.voiceInteractor, startFlags, checkedOptions,
                 inTask, inTaskFragment, restrictedBgActivity, intentGrants);
 
         if (request.outActivity != null) {
@@ -1640,7 +1642,7 @@
      */
     private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
+            int startFlags, ActivityOptions options, Task inTask,
             TaskFragment inTaskFragment, boolean restrictedBgActivity,
             NeededUriGrants intentGrants) {
         int result = START_CANCELED;
@@ -1664,7 +1666,7 @@
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
                 result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
-                        startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
+                        startFlags, options, inTask, inTaskFragment, restrictedBgActivity,
                         intentGrants);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -1808,10 +1810,10 @@
     @VisibleForTesting
     int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
+            int startFlags, ActivityOptions options, Task inTask,
             TaskFragment inTaskFragment, boolean restrictedBgActivity,
             NeededUriGrants intentGrants) {
-        setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,
+        setInitialState(r, options, inTask, inTaskFragment, startFlags, sourceRecord,
                 voiceSession, voiceInteractor, restrictedBgActivity);
 
         computeLaunchingTaskFlags();
@@ -2429,7 +2431,7 @@
     }
 
     private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
-            TaskFragment inTaskFragment, boolean doResume, int startFlags,
+            TaskFragment inTaskFragment, int startFlags,
             ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession,
             IVoiceInteractor voiceInteractor, boolean restrictedBgActivity) {
         reset(false /* clearRequest */);
@@ -2494,10 +2496,11 @@
         // If the caller has asked not to resume at this point, we make note
         // of this in the record so that we can skip it when trying to find
         // the top running activity.
-        mDoResume = doResume;
-        if (!doResume || !r.showToCurrentUser() || mLaunchTaskBehind) {
+        if (!r.showToCurrentUser() || mLaunchTaskBehind) {
             r.delayedResume = true;
             mDoResume = false;
+        } else {
+            mDoResume = true;
         }
 
         if (mOptions != null) {
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 804ccc5..3d40f64 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -18,7 +18,6 @@
     name: "services.net",
     defaults: ["platform_service_defaults"],
     srcs: [
-        ":net-module-utils-srcs",
         ":services.net-sources",
     ],
     static_libs: [
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
new file mode 100644
index 0000000..c7ccef2
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2022 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.server.job.controllers;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManagerInternal;
+import android.os.Looper;
+import android.util.ArraySet;
+
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+
+public class FlexibilityControllerTest {
+    private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests";
+    private static final int SOURCE_USER_ID = 0;
+
+    private MockitoSession mMockingSession;
+    private FlexibilityController mFlexibilityController;
+    @Mock
+    private AlarmManager mAlarmManager;
+    @Mock
+    private Context mContext;
+    @Mock
+    private JobSchedulerService mJobSchedulerService;
+    private JobStore mJobStore;
+
+    @Before
+    public void setup() {
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .mockStatic(LocalServices.class)
+                .startMocking();
+        // Called in StateController constructor.
+        when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
+        when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
+        when(mJobSchedulerService.getConstants()).thenReturn(
+                mock(JobSchedulerService.Constants.class));
+        // Called in FlexibilityController constructor.
+        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+        when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+        //used to get jobs by UID
+        mJobStore = JobStore.initAndGetForTesting(mContext, mContext.getFilesDir());
+        when(mJobSchedulerService.getJobStore()).thenReturn(mJobStore);
+        // Used in JobStatus.
+        doReturn(mock(PackageManagerInternal.class))
+                .when(() -> LocalServices.getService(PackageManagerInternal.class));
+        // Freeze the clocks at a moment in time
+        JobSchedulerService.sSystemClock =
+                Clock.fixed(Instant.ofEpochMilli(100L), ZoneOffset.UTC);
+        JobSchedulerService.sElapsedRealtimeClock =
+                Clock.fixed(Instant.ofEpochMilli(100L), ZoneOffset.UTC);
+        // Initialize real objects.
+        mFlexibilityController = new FlexibilityController(mJobSchedulerService);
+    }
+
+    @After
+    public void teardown() {
+        if (mMockingSession != null) {
+            mMockingSession.finishMocking();
+        }
+    }
+
+    private static JobInfo.Builder createJob(int id) {
+        return new JobInfo.Builder(id, new ComponentName("foo", "bar"));
+    }
+
+    private JobStatus createJobStatus(String testTag, JobInfo.Builder job) {
+        JobInfo jobInfo = job.build();
+        return JobStatus.createFromJobInfo(
+                jobInfo, 1000, SOURCE_PACKAGE, SOURCE_USER_ID, testTag);
+    }
+
+    @Test
+    public void testGetNextConstraintDropTimeElapsed() {
+        long nextTimeToDropNumConstraints;
+
+        // no delay, deadline
+        JobInfo.Builder jb = createJob(0).setOverrideDeadline(1000);
+        JobStatus js = createJobStatus("time", jb);
+        js.enqueueTime = 100L;
+
+        assertEquals(0, js.getEarliestRunTime());
+        assertEquals(1100L, js.getLatestRunTimeElapsed());
+        assertEquals(100L, js.enqueueTime);
+
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(600L, nextTimeToDropNumConstraints);
+        js.adjustNumRequiredFlexibleConstraints(-1);
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(700L, nextTimeToDropNumConstraints);
+        js.adjustNumRequiredFlexibleConstraints(-1);
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(800L, nextTimeToDropNumConstraints);
+
+        // delay, no deadline
+        jb = createJob(0).setMinimumLatency(800000L);
+        js = createJobStatus("time", jb);
+        js.enqueueTime = 100L;
+
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(130400100, nextTimeToDropNumConstraints);
+        js.adjustNumRequiredFlexibleConstraints(-1);
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(156320100L, nextTimeToDropNumConstraints);
+        js.adjustNumRequiredFlexibleConstraints(-1);
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(182240100L, nextTimeToDropNumConstraints);
+
+        // no delay, no deadline
+        jb = createJob(0);
+        js = createJobStatus("time", jb);
+        js.enqueueTime = 100L;
+
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(129600100, nextTimeToDropNumConstraints);
+        js.adjustNumRequiredFlexibleConstraints(-1);
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(155520100L, nextTimeToDropNumConstraints);
+        js.adjustNumRequiredFlexibleConstraints(-1);
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(181440100L, nextTimeToDropNumConstraints);
+
+        // delay, deadline
+        jb = createJob(0).setOverrideDeadline(1100).setMinimumLatency(100);
+        js = createJobStatus("time", jb);
+        js.enqueueTime = 100L;
+
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(700L, nextTimeToDropNumConstraints);
+        js.adjustNumRequiredFlexibleConstraints(-1);
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(800L, nextTimeToDropNumConstraints);
+        js.adjustNumRequiredFlexibleConstraints(-1);
+        nextTimeToDropNumConstraints = mFlexibilityController.getNextConstraintDropTimeElapsed(js);
+        assertEquals(900L, nextTimeToDropNumConstraints);
+    }
+
+    @Test
+    public void testWontStopJobFromRunning() {
+        JobStatus js = createJobStatus("testWontStopJobFromRunning", createJob(101));
+        // Stop satisfied constraints from causing a false positive.
+        js.adjustNumRequiredFlexibleConstraints(100);
+        synchronized (mFlexibilityController.mLock) {
+            when(mJobSchedulerService.isCurrentlyRunningLocked(js)).thenReturn(true);
+            assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(js));
+        }
+    }
+
+    @Test
+    public void testFlexibilityTracker() {
+        FlexibilityController.FlexibilityTracker flexTracker =
+                mFlexibilityController.new
+                        FlexibilityTracker(FlexibilityController.FLEXIBLE_CONSTRAINTS);
+
+        JobStatus[] jobs = new JobStatus[4];
+        JobInfo.Builder jb;
+        for (int i = 0; i < jobs.length; i++) {
+            jb = createJob(i);
+            if (i > 0) {
+                jb.setRequiresDeviceIdle(true);
+            }
+            if (i > 1) {
+                jb.setRequiresBatteryNotLow(true);
+            }
+            if (i > 2) {
+                jb.setRequiresCharging(true);
+            }
+            jobs[i] = createJobStatus("", jb);
+            flexTracker.add(jobs[i]);
+
+        }
+
+        ArrayList<ArraySet<JobStatus>> trackedJobs = flexTracker.getArrayList();
+        assertEquals(1, trackedJobs.get(0).size());
+        assertEquals(1, trackedJobs.get(1).size());
+        assertEquals(1, trackedJobs.get(2).size());
+        assertEquals(0, trackedJobs.get(3).size());
+
+        flexTracker.adjustJobsRequiredConstraints(jobs[0], -1);
+        assertEquals(1, trackedJobs.get(0).size());
+        assertEquals(2, trackedJobs.get(1).size());
+        assertEquals(0, trackedJobs.get(2).size());
+        assertEquals(0, trackedJobs.get(3).size());
+
+        flexTracker.adjustJobsRequiredConstraints(jobs[0], -1);
+        assertEquals(2, trackedJobs.get(0).size());
+        assertEquals(1, trackedJobs.get(1).size());
+        assertEquals(0, trackedJobs.get(2).size());
+        assertEquals(0, trackedJobs.get(3).size());
+
+        flexTracker.adjustJobsRequiredConstraints(jobs[0], -1);
+        assertEquals(1, trackedJobs.get(0).size());
+        assertEquals(1, trackedJobs.get(1).size());
+        assertEquals(0, trackedJobs.get(2).size());
+        assertEquals(0, trackedJobs.get(3).size());
+
+        flexTracker.remove(jobs[1]);
+        assertEquals(1, trackedJobs.get(0).size());
+        assertEquals(0, trackedJobs.get(1).size());
+        assertEquals(0, trackedJobs.get(2).size());
+        assertEquals(0, trackedJobs.get(3).size());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
index c3d40da..208f99a 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
@@ -45,7 +45,9 @@
 
     private static final int ARBITRARY_USER_ID = 99999;
     private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234;
-    private static final Instant ARBITRARY_AUTO_TIME_LOWER_BOUND = Instant.ofEpochMilli(0);
+    private static final Instant ARBITRARY_SUGGESTION_LOWER_BOUND = Instant.ofEpochMilli(0);
+    private static final Instant ARBITRARY_SUGGESTION_UPPER_BOUND =
+            Instant.ofEpochMilli(Long.MAX_VALUE);
     private static final @Origin int[] ARBITRARY_ORIGIN_PRIORITIES = { ORIGIN_NETWORK };
 
     /**
@@ -59,9 +61,10 @@
                 .setUserConfigAllowed(true)
                 .setAutoDetectionSupported(true)
                 .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
-                .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND)
+                .setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
+                .setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
+                .setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND)
                 .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
-                .setDeviceHasY2038Issue(true)
                 .setAutoDetectionEnabledSetting(true)
                 .build();
         {
@@ -110,9 +113,10 @@
                 .setUserConfigAllowed(false)
                 .setAutoDetectionSupported(true)
                 .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
-                .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND)
+                .setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
+                .setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
+                .setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND)
                 .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
-                .setDeviceHasY2038Issue(true)
                 .setAutoDetectionEnabledSetting(true)
                 .build();
         {
@@ -159,9 +163,10 @@
                 .setUserConfigAllowed(true)
                 .setAutoDetectionSupported(false)
                 .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
-                .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND)
+                .setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
+                .setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
+                .setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND)
                 .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
-                .setDeviceHasY2038Issue(true)
                 .setAutoDetectionEnabledSetting(true)
                 .build();
         {
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index b9c74ba..67c8c4f 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -69,7 +69,9 @@
 
     private static final int ARBITRARY_USER_ID = 9999;
     private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234;
-    private static final Instant ARBITRARY_AUTO_TIME_LOWER_BOUND = Instant.ofEpochMilli(0);
+    private static final Instant ARBITRARY_SUGGESTION_LOWER_BOUND = Instant.ofEpochMilli(0);
+    private static final Instant ARBITRARY_SUGGESTION_UPPER_BOUND =
+            Instant.ofEpochMilli(Long.MAX_VALUE);
     private static final int[] ARBITRARY_ORIGIN_PRIORITIES = { ORIGIN_NETWORK };
 
     private Context mMockContext;
@@ -444,9 +446,10 @@
                 .setUserConfigAllowed(true)
                 .setAutoDetectionSupported(true)
                 .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
-                .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND)
+                .setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
+                .setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
+                .setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND)
                 .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
-                .setDeviceHasY2038Issue(true)
                 .setAutoDetectionEnabledSetting(autoDetectionEnabled)
                 .build();
     }
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index aeb5c65..1aea672 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -53,7 +53,16 @@
 
     private static final @UserIdInt int ARBITRARY_USER_ID = 9876;
     private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234;
-    private static final Instant TIME_LOWER_BOUND = createUnixEpochTime(2009, 1, 1, 12, 0, 0);
+    private static final Instant DEFAULT_SUGGESTION_LOWER_BOUND =
+            createUnixEpochTime(2005, 1, 1, 1, 0, 0);
+    /** A value after {@link #DEFAULT_SUGGESTION_LOWER_BOUND} */
+    private static final Instant TEST_SUGGESTION_LOWER_BOUND =
+            createUnixEpochTime(2006, 1, 1, 1, 0, 0);
+    private static final Instant DEFAULT_SUGGESTION_UPPER_BOUND =
+            createUnixEpochTime(2099, 12, 1, 1, 0, 0);
+    /** A value before {@link #DEFAULT_SUGGESTION_UPPER_BOUND} */
+    private static final Instant TEST_SUGGESTION_UPPER_BOUND =
+            createUnixEpochTime(2037, 12, 1, 1, 0, 0);
 
     private static final TimestampedValue<Instant> ARBITRARY_CLOCK_INITIALIZATION_INFO =
             new TimestampedValue<>(
@@ -77,9 +86,10 @@
                     .setAutoDetectionSupported(true)
                     .setSystemClockUpdateThresholdMillis(
                             ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
-                    .setAutoTimeLowerBound(TIME_LOWER_BOUND)
+                    .setAutoSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND)
+                    .setManualSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND)
+                    .setSuggestionUpperBound(DEFAULT_SUGGESTION_UPPER_BOUND)
                     .setOriginPriorities(ORIGIN_PRIORITIES)
-                    .setDeviceHasY2038Issue(true)
                     .setAutoDetectionEnabledSetting(false)
                     .build();
 
@@ -89,9 +99,10 @@
                     .setAutoDetectionSupported(true)
                     .setSystemClockUpdateThresholdMillis(
                             ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
-                    .setAutoTimeLowerBound(TIME_LOWER_BOUND)
+                    .setAutoSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND)
+                    .setManualSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND)
+                    .setSuggestionUpperBound(DEFAULT_SUGGESTION_UPPER_BOUND)
                     .setOriginPriorities(ORIGIN_PRIORITIES)
-                    .setDeviceHasY2038Issue(true)
                     .setAutoDetectionEnabledSetting(true)
                     .build();
 
@@ -344,22 +355,6 @@
     }
 
     @Test
-    public void telephonyTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
-        Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
-
-        int slotIndex = ARBITRARY_SLOT_INDEX;
-        Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
-
-        TelephonyTimeSuggestion timeSuggestion =
-                script.generateTelephonyTimeSuggestion(
-                        slotIndex, suggestedTime);
-
-        script.simulateTelephonyTimeSuggestion(timeSuggestion)
-                .verifySystemClockWasNotSetAndResetCallTracking()
-                .assertLatestTelephonySuggestion(slotIndex, null);
-    }
-
-    @Test
     public void testSuggestTelephonyTime_timeDetectionToggled() {
         final int clockIncrementMillis = 100;
         final int systemClockUpdateThresholdMillis = 2000;
@@ -453,6 +448,70 @@
     }
 
     @Test
+    public void testSuggestTelephonyTime_rejectedBelowLowerBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+                        .setOriginPriorities(ORIGIN_TELEPHONY)
+                        .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
+        TelephonyTimeSuggestion timeSuggestion =
+                script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, belowLowerBound);
+        script.simulateTelephonyTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestTelephonyTime_notRejectedAboveLowerBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_TELEPHONY)
+                        .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
+        TelephonyTimeSuggestion timeSuggestion =
+                script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, aboveLowerBound);
+        script.simulateTelephonyTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
+    }
+
+    @Test
+    public void testSuggestTelephonyTime_rejectedAboveUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_TELEPHONY)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
+        TelephonyTimeSuggestion timeSuggestion =
+                script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, aboveUpperBound);
+        script.simulateTelephonyTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestTelephonyTime_notRejectedBelowUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_TELEPHONY)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
+        TelephonyTimeSuggestion timeSuggestion =
+                script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, belowUpperBound);
+        script.simulateTelephonyTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
+    }
+
+    @Test
     public void testSuggestManualTime_autoTimeDisabled() {
         Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED);
 
@@ -530,7 +589,7 @@
     }
 
     @Test
-    public void manualTimeSuggestion_isIgnored_whenAutoTimeEnabled() {
+    public void testSuggestManualTime_isIgnored_whenAutoTimeEnabled() {
         Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
 
         ManualTimeSuggestion timeSuggestion =
@@ -543,16 +602,63 @@
     }
 
     @Test
-    public void manualTimeSuggestion_ignoresTimeLowerBound() {
-        Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED);
-        Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+    public void testSuggestManualTime_rejectedAboveUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
 
-        ManualTimeSuggestion timeSuggestion =
-                script.generateManualTimeSuggestion(suggestedTime);
-
+        Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
+        ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(aboveUpperBound);
         script.simulateManualTimeSuggestion(
-                ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
-                .verifySystemClockWasSetAndResetCallTracking(suggestedTime.toEpochMilli());
+                        ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestManualTime_notRejectedBelowUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
+        ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(belowUpperBound);
+        script.simulateManualTimeSuggestion(
+                        ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
+                .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
+    }
+
+    @Test
+    public void testSuggestManualTime_rejectedBelowLowerBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+                        .setManualSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
+        ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(belowLowerBound);
+        script.simulateManualTimeSuggestion(
+                        ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestManualTimes_notRejectedAboveLowerBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+                        .setManualSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
+        ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(aboveLowerBound);
+        script.simulateManualTimeSuggestion(
+                        ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
+                .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
     }
 
     @Test
@@ -591,20 +697,67 @@
     }
 
     @Test
-    public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
+    public void testSuggestNetworkTime_rejectedBelowLowerBound() {
         ConfigurationInternal configInternal =
                 new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
                         .setOriginPriorities(ORIGIN_NETWORK)
+                        .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
                         .build();
         Script script = new Script().simulateConfigurationInternalChange(configInternal);
 
-        Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+        Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
         NetworkTimeSuggestion timeSuggestion =
-                script.generateNetworkTimeSuggestion(suggestedTime);
-
+                script.generateNetworkTimeSuggestion(belowLowerBound);
         script.simulateNetworkTimeSuggestion(timeSuggestion)
-                .verifySystemClockWasNotSetAndResetCallTracking()
-                .assertLatestNetworkSuggestion(null);
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestNetworkTime_notRejectedAboveLowerBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_NETWORK)
+                        .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
+        NetworkTimeSuggestion timeSuggestion =
+                script.generateNetworkTimeSuggestion(aboveLowerBound);
+        script.simulateNetworkTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
+    }
+
+    @Test
+    public void testSuggestNetworkTime_rejectedAboveUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_NETWORK)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
+        NetworkTimeSuggestion timeSuggestion =
+                script.generateNetworkTimeSuggestion(aboveUpperBound);
+        script.simulateNetworkTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestNetworkTime_notRejectedBelowUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_NETWORK)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
+        NetworkTimeSuggestion timeSuggestion =
+                script.generateNetworkTimeSuggestion(belowUpperBound);
+        script.simulateNetworkTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
     }
 
     @Test
@@ -643,6 +796,70 @@
     }
 
     @Test
+    public void testSuggestGnssTime_rejectedBelowLowerBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_GNSS)
+                        .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
+        GnssTimeSuggestion timeSuggestion =
+                script.generateGnssTimeSuggestion(belowLowerBound);
+        script.simulateGnssTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestGnssTime_notRejectedAboveLowerBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_GNSS)
+                        .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
+        GnssTimeSuggestion timeSuggestion =
+                script.generateGnssTimeSuggestion(aboveLowerBound);
+        script.simulateGnssTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
+    }
+
+    @Test
+    public void testSuggestGnssTime_rejectedAboveUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_GNSS)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
+        GnssTimeSuggestion timeSuggestion =
+                script.generateGnssTimeSuggestion(aboveUpperBound);
+        script.simulateGnssTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestGnssTime_notRejectedBelowUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_GNSS)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
+        GnssTimeSuggestion timeSuggestion =
+                script.generateGnssTimeSuggestion(belowUpperBound);
+        script.simulateGnssTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
+    }
+
+    @Test
     public void testSuggestExternalTime_autoTimeEnabled() {
         ConfigurationInternal configInternal =
                 new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
@@ -678,20 +895,67 @@
     }
 
     @Test
-    public void externalTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
+    public void testSuggestExternalTime_rejectedBelowLowerBound() {
         ConfigurationInternal configInternal =
                 new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
                         .setOriginPriorities(ORIGIN_EXTERNAL)
+                        .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
                         .build();
         Script script = new Script().simulateConfigurationInternalChange(configInternal);
 
-        Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+        Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
         ExternalTimeSuggestion timeSuggestion =
-                script.generateExternalTimeSuggestion(suggestedTime);
-
+                script.generateExternalTimeSuggestion(belowLowerBound);
         script.simulateExternalTimeSuggestion(timeSuggestion)
-                .verifySystemClockWasNotSetAndResetCallTracking()
-                .assertLatestExternalSuggestion(null);
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestExternalTime_notRejectedAboveLowerBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_EXTERNAL)
+                        .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
+        ExternalTimeSuggestion timeSuggestion =
+                script.generateExternalTimeSuggestion(aboveLowerBound);
+        script.simulateExternalTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
+    }
+
+    @Test
+    public void testSuggestExternalTime_rejectedAboveUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_EXTERNAL)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
+        ExternalTimeSuggestion timeSuggestion =
+                script.generateExternalTimeSuggestion(aboveUpperBound);
+        script.simulateExternalTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestExternalTime_notRejectedBelowUpperBound() {
+        ConfigurationInternal configInternal =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+                        .setOriginPriorities(ORIGIN_EXTERNAL)
+                        .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
+                        .build();
+        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
+        ExternalTimeSuggestion timeSuggestion =
+                script.generateExternalTimeSuggestion(belowUpperBound);
+        script.simulateExternalTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
     }
 
     @Test
@@ -1198,56 +1462,6 @@
                 .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
     }
 
-    @Test
-    public void manualY2038SuggestionsAreRejectedOnAffectedDevices() {
-        ConfigurationInternal configInternal =
-                new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
-                        .setOriginPriorities(ORIGIN_TELEPHONY)
-                        .setDeviceHasY2038Issue(true)
-                        .build();
-        Script script = new Script().simulateConfigurationInternalChange(configInternal);
-
-        Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
-        ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(y2038IssueTime);
-        script.simulateManualTimeSuggestion(
-                ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
-                .verifySystemClockWasNotSetAndResetCallTracking();
-    }
-
-    @Test
-    public void telephonyY2038SuggestionsAreRejectedOnAffectedDevices() {
-        ConfigurationInternal configInternal =
-                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
-                        .setOriginPriorities(ORIGIN_TELEPHONY)
-                        .setDeviceHasY2038Issue(true)
-                        .build();
-        Script script = new Script().simulateConfigurationInternalChange(configInternal);
-
-        final int slotIndex = 0;
-        Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
-        TelephonyTimeSuggestion timeSuggestion =
-                script.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime);
-        script.simulateTelephonyTimeSuggestion(timeSuggestion)
-                .verifySystemClockWasNotSetAndResetCallTracking();
-    }
-
-    @Test
-    public void telephonyY2038SuggestionsAreNotRejectedOnUnaffectedDevices() {
-        ConfigurationInternal configInternal =
-                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
-                        .setOriginPriorities(ORIGIN_TELEPHONY)
-                        .setDeviceHasY2038Issue(false)
-                        .build();
-        Script script = new Script().simulateConfigurationInternalChange(configInternal);
-
-        final int slotIndex = 0;
-        Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
-        TelephonyTimeSuggestion timeSuggestion =
-                script.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime);
-        script.simulateTelephonyTimeSuggestion(timeSuggestion)
-                .verifySystemClockWasSetAndResetCallTracking(y2038IssueTime.toEpochMilli());
-    }
-
     /**
      * A fake implementation of {@link TimeDetectorStrategyImpl.Environment}. Besides tracking
      * changes and behaving like the real thing should, it also asserts preconditions.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index fe3c26a..cd087e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1406,7 +1406,7 @@
             ActivityRecord source, ActivityOptions options, Task inTask,
             TaskFragment inTaskFragment) {
         starter.startActivityInner(target, source, null /* voiceSession */,
-                null /* voiceInteractor */, 0 /* startFlags */, true /* doResume */,
+                null /* voiceInteractor */, 0 /* startFlags */,
                 options, inTask, inTaskFragment, false /* restrictedBgActivity */,
                 null /* intentGrants */);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index 47c2176..21197ba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -184,7 +184,6 @@
                 /* voiceSession */null,
                 /* voiceInteractor */ null,
                 /* startFlags */ 0,
-                /* doResume */true,
                 /* options */null,
                 /* inTask */null,
                 /* inTaskFragment */ null,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
index 0f809ee..470fa58 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
@@ -193,18 +193,22 @@
     }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Visibility changes depending on orientation and navigation mode")
     override fun navBarLayerIsVisibleAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Visibility changes depending on orientation and navigation mode")
     override fun navBarLayerPositionAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Visibility changes depending on orientation and navigation mode")
     override fun statusBarLayerPositionAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Visibility changes depending on orientation and navigation mode")
     override fun statusBarLayerIsVisibleAtStartAndEnd() { }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index 242a884..220e4ca 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -91,6 +91,7 @@
     override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow()
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Display is off at the start")
     override fun navBarLayerPositionAtStartAndEnd() { }
 
@@ -105,6 +106,7 @@
     }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Display is off at the start")
     override fun statusBarLayerPositionAtStartAndEnd() { }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index 3619505..9ed1bde 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -117,6 +117,7 @@
         super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun navBarLayerPositionAtStartAndEnd() { }
 
@@ -131,6 +132,7 @@
     }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun statusBarLayerPositionAtStartAndEnd() { }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
index 5a4b369..1d8b0a6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
@@ -102,18 +102,22 @@
     override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun navBarLayerPositionAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun statusBarLayerPositionAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun taskBarLayerIsVisibleAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun taskBarWindowIsAlwaysVisible() { }
 
@@ -135,6 +139,7 @@
     fun statusBarLayerPositionAtEnd() = testSpec.statusBarLayerPositionAtEnd()
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun statusBarLayerIsVisibleAtStartAndEnd() { }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index c03cb56..1ad5426 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -132,22 +132,27 @@
     }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun taskBarLayerIsVisibleAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun navBarLayerIsVisibleAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun taskBarWindowIsAlwaysVisible() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun navBarWindowIsAlwaysVisible() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun statusBarWindowIsAlwaysVisible() { }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index b2a2381..1e3caa4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -164,14 +164,17 @@
     }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. App is full screen")
     override fun statusBarLayerPositionAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. App is full screen")
     override fun statusBarLayerIsVisibleAtStartAndEnd() { }
 
     /** {@inheritDoc} */
+    @Test
     @Ignore("Not applicable to this CUJ. App is full screen")
     override fun statusBarWindowIsAlwaysVisible() { }